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

C 指针变量周围是否需要互斥锁?,c,linux,multithreading,pointers,mutex,C,Linux,Multithreading,Pointers,Mutex,在涉及指针间接寻址(指针指向关键部分的数据)的代码段周围是否需要互斥锁?示例代码: 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) {

在涉及指针间接寻址(指针指向关键部分的数据)的代码段周围是否需要互斥锁?示例代码:

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
执行的其他操作。例如,另一个线程根据
s->i
的内容修改
s->c
的值:

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

在这种情况下,您不能忽略互斥锁,否则您可能会将
s->i
设置为1,将
s->c
设置为“y”。

没有提供足够的信息来给出真正好的答案。
s
如何“发布”到其他线程?其他线程如何“订阅”
s
struct s
对象存储在什么数据结构中

因此,我将给出一个一般性的回答:

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

关于指针:

您可能听说过,在一些常见的CPU上,正确对齐的指针的加载/存储是原子的(并非所有CPU或所有类型的指针都是原子的,例如:x86上的远指针是非原子的)。如果您对CPU/VM内存模型没有透彻的了解,请不要使用它。如果您不使用锁,可能会出现许多微妙的问题(锁提供了非常有力的保证)

编辑: 在您的示例中,无论是
th1
还是
th2
都不会修改列表,它们只会修改列表的元素。因此,在这种特定情况下,不需要锁定列表,只需要锁定列表的元素(指针概念上属于链表实现)

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

有几种方法可以实现此锁定

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

当您有钥匙时,需要一把锁。忘记指针或无指针。这是有效代码吗?函数声明及其定义之间的参数列表不同于
int modify_struct(struct s*sptr)
不同于
int modify_struct
。就我个人而言,我不认为后者是有效的功能。但也许我遗漏了一些明显的东西here@knittl你是对的。在编写问题的过程中,我更改了代码,将函数调用更改为函数定义,并忘记用参数列表替换变量。我甚至试图解释我的错误。我真傻。我现在已经编辑过了。谢谢。:)没问题:)只是想确保这不是我在C语言中一直错过的东西谢谢你的回答。我是一个新手,从来没有想到我实际上是在处理一个局部变量。现在回想起来,我的问题看起来真的很愚蠢。难怪谷歌没有返回任何结果。我在那里没有看到任何局部变量。@ninjalj:好的,这是一个函数参数:P。不过我的观点仍然适用。谢谢。我不确定指向共享数据的指针是否也很重要。我已经修改了问题中的代码。你认为这就足够发表更具体的评论了吗?谢谢,我在看锁。有趣的是,它们也可以分层应用。因此,根据您的解释,如果我有另一个线程来操作列表(add after/add before/delete元素),那么在这种情况下,我还需要锁定
next
指针?您将锁定列表,这将保护整个列表数据结构(即所有下一个指针,加上所有元素)。分层锁可以看作是对上述全局锁的优化,它降低了更多的并发性。