是否需要在涉及指针间接寻址(其中指针指向属于临界区的数据)的一段代码周围使用互斥锁?示例代码:
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
如何“发布”到其他线程?其他线程如何“订阅”?
struct s
对象存储在什么数据结构中?
所以,我会给出一个通用的答案:
线程之间共享的每种数据都需要同步。这包括共享指针。
关于指针:
您可能听说过,在一些常见的 CPU 上,正确对齐的指针的加载/存储是原子的(并非所有 CPU 或所有类型的指针都是这种情况,例如:x86 上的远指针是非原子的)。如果您对您的 CPU/VM 内存模型没有透彻的了解,请远离使用它,如果您不使用锁(锁提供了非常强大的保证),则有许多细微的事情可能会出错。
编辑:
在您的示例中,th1
和th2
都没有修改列表,它们只修改了列表的元素。因此,在这种特定情况下,您不需要锁定列表,您只需要锁定列表的元素(指针在概念上属于链表实现)。
在更典型的情况下,一些线程会遍历列表,而其他线程会修改列表(添加和删除元素)。这需要锁定列表,或者使用某种无锁算法。
有几种方法可以进行这种锁定。
- 对列表进行全局锁定,并将其用于列表的元素。
- 使用分层锁定,对列表进行锁定,对每个元素进行锁定。要读取/修改一个元素,您首先要锁定列表,找到元素,获取元素的锁,释放列表的锁,处理元素,最后释放元素的锁。如果您需要对元素进行一些复杂的处理并且不想阻止其他线程访问列表,这将很有用。 您必须注意始终以相同的顺序获取锁,以避免死锁。
关于c - 指针变量周围是否需要互斥锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5612914/