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

发布于 2024-10-31 04:53:11 字数 1452 浏览 1 评论 0原文

涉及指针间接(其中指针指向属于关键部分的数据)的代码部分是否需要互斥锁?示例代码:

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);
}

Is a mutex lock needed around a section of code that involves pointer indirection (where the pointer points to data that is part of a critical section)? An example code:

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);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

淑女气质 2024-11-07 04:53:11

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

因此,我将给出一个通用的答案:

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

关于指针:

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

编辑:

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

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

有多种方法可以实现这种锁定。

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

There's not enough information given to give a really good answer. How is s "published" to other threads? How do other threads "subscribe" to s? In what data structure are struct s objects stored?

So, I'll give a generic answer:

Every kind of data that is shared between threads needs synchronization. This includes shared pointers.

About pointers:

You may have heard that on some commonplace CPUs loads/stores of correctly aligned pointers are atomic (this is not the case for all CPUs or for all kinds of pointers, e.g: far pointers on x86 are non-atomic). Stay away from using this if you don't have a thorough understanding of your CPU/VM memory model, there are many subtle things that can go wrong if you don't take locks (locks provide pretty strong guarantees).

Edit:

In your example, neither th1 nor th2 modifies the list, they only modify elements of the list. So, in this specific case, you don't need to lock the list, you just need to lock elements of the list (the pointer conceptually belongs to the linked list implementation).

In more typical cases, some threads would be traversing the list, while others would be modifying the list (adding and removing elements). This requires locking the list, or using some kind of lock-free algorithm.

There are several ways of doing this locking.

  • Have a global lock on the list, and use it also for elements of the list.
  • Use hierarchical locking, have a lock on the list, and a lock on every element. To read/modify an element, you would first take a lock on the list, find the element, take the element's lock, release the list's lock, process the element, and finally release the element's lock. This is useful if you need to do some complex processing on the element and don't want to prevent other threads from accessing the list. You have to take care to always take the locks in the same order, to avoid deadlocks.
丢了幸福的猪 2024-11-07 04:53:11

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

Locks are used to protect critical section in the code. If your variable is in critical section, then you will need to protect it with some kind of lock.

葬花如无物 2024-11-07 04:53:11

这取决于您对 s 可能进行的其他操作。例如,另一个线程根据 s->i 修改 s->c 的值:

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

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

It depends on what other operations you may have on s. For example, another thread modifying value of s->c depending on what s->i is:

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

In this case you cannot omit the mutex lock otherwise you may have both s->i set to 1 and s->c set to 'y'.

一袭水袖舞倾城 2024-11-07 04:53:11

锁用于保护关键部分。它与变量是否是指针无关。

就您而言,您不需要锁定该支票。由于 s 是一个参数,因此无法从函数外部访问它。但是,它指向的数据对于您的函数来说不是本地的,因此您可能需要锁定对该数据的访问。

A lock is used to protect critical sections. It has nothing to do with a variable being a pointer or not.

In your case, you don't need to lock that check. Because s is a parameter it cannot be accessed from outside your function. However, the data pointed by it is not local to your function, so you might need to lock access to that data.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文