繁体   English   中英

指针变量周围是否需要互斥锁?

[英]Is a mutex lock needed around a pointer variable?

是否需要在涉及指针间接的代码段周围使用互斥锁(其中指针指向属于临界区的数据)? 示例代码:

struct list {
    int i;
    struct list *next;
};

int modify_second_elem(struct list *head, int val);
void * func1(void *ptr);
void * func2(void *ptr);

int modify_second_elem(struct list *head, int val) {

    if(head == NULL)
        return 1;

    /* Check to see if second element exists.
       Here, I am using indirection to get the next pointer.
       Would I need synchronization here? */
    if(head->next == NULL)
        return -1;

    pthread_mutex_lock(&list_lock);
    (head->next)->i = val;
    pthread_mutex_unlock(&list_lock);

    return 0;

}

void * func1(void *ptr) {
    struct list *head;
    head = (struct list *) ptr;
    modify_second_elem(head, 4);
}

void * func2(void *ptr) {
    struct list *head;
    head = (struct list *) ptr;
    modify_second_elem(head, 6);
}

void main() {
    struct list *el1, *el2, *el3;
    pthread_t th1, th2;

    el1 = (struct list *) malloc(sizeof(list));
    el2 = (struct list *) malloc(sizeof(list));
    el3 = (struct list *) malloc(sizeof(list));

    el1->i = 1;
    el1->next = el2;
    el2->i = 2;
    el2->next = el3;
    el3->i = 3;
    el3->next = NULL;

    pthread_create(&th1, NULL, &func1, (void *) el1);
    pthread_create(&th2, NULL, &func2, (void *) el1);

    pthread_join(th1, NULL);
    pthread_join(th2, NULL);

    exit(EXIT_SUCCESS);
}

锁用于保护代码中的关键部分 如果您的变量处于临界区,那么您需要使用某种锁来保护它。

没有足够的信息给出一个非常好的答案。 如何s “上发表”给其他线程? 其他线程如何“订阅” s struct s对象存储在什么数据结构中?

所以,我会给出一个通用答案:

线程之间共享的每种数据都需要同步。 这包括共享指针。

关于指针:

您可能听说过,在一些普通的CPU上,正确对齐的指针的加载/存储是原子的(对于所有CPU或所有类型的指针都不是这种情况,例如:x86上的远指针是非原子的)。 如果你没有彻底了解你的CPU / VM内存模型,请远离使用它,如果你不采取锁定(锁提供相当强的保证),有许多微妙的事情可能会出错。

编辑:

在您的示例中, th1th2都不修改列表,它们只修改列表的元素。 因此,在这种特定情况下,您不需要锁定列表,只需要锁定列表的元素(指针在概念上属于链表实现)。

在更典型的情况下,一些线程将遍历列表,而其他线程将修改列表(添加和删除元素)。 这需要锁定列表,或使用某种无锁算法。

有几种方法可以执行此锁定。

  • 对列表进行全局锁定 ,并将其用于列表的元素。
  • 使用分层锁定 ,锁定列表,并锁定每个元素。 要读取/修改元素,首先要锁定列表,找到元素,获取元素的锁定,释放列表的锁定,处理元素,最后释放元素的锁定。 如果您需要对元素执行一些复杂的处理并且不希望阻止其他线程访问列表,这将非常有用。 您必须注意始终以相同的顺序取锁 ,以避免死锁。

锁用于保护关键部分 它与作为指针的变量无关。

在您的情况下,您不需要锁定该检查。 因为s是参数,所以无法从函数外部访问它。 但是, 它指向的数据不是您的函数的本地数据 ,因此您可能需要锁定对该数据的访问。

这要看你可能有什么其他的操作s 例如,另一个线程修改s->c值取决于s->i是:

if (s->i == 1) {
    s->c = 'x';
} else {
    s->c = 'y';
}

在这种情况下,您不能省略互斥锁,否则您可能同时将s->i设置为1并将s->c设置为'y'。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM