c - 为什么 Helgrind 显示 "lock order violated"错误消息?

标签 c multithreading pthreads valgrind deadlock

请看下面的代码

    #include <stdio.h>
    #include <pthread.h>
    #include <assert.h>
    #include <stdlib.h>

    pthread_mutex_t g = PTHREAD_MUTEX_INITIALIZER;
    pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER;
    pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER;

    void* worker(void* arg) 
    {
        pthread_mutex_lock(&g);

        if ((long long) arg == 0) {
        pthread_mutex_lock(&m1);
        pthread_mutex_lock(&m2);
        } else {
        pthread_mutex_lock(&m2);
        pthread_mutex_lock(&m1);
        }
        pthread_mutex_unlock(&m1);
        pthread_mutex_unlock(&m2);

        pthread_mutex_unlock(&g);
        return NULL;
    }

    int main(int argc, char *argv[]) {
        pthread_t p1, p2;
        pthread_create(&p1, NULL, worker, (void *) (long long) 0);
        pthread_create(&p2, NULL, worker, (void *) (long long) 1);
        pthread_join(p1, NULL);
        pthread_join(p2, NULL);
        return 0;
    }

Helgrind 抛出以下错误:
==10035== Helgrind, a thread error detector
==10035== Copyright (C) 2007-2017, and GNU GPL'd, by OpenWorks LLP et al.
==10035== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==10035== Command: ./Hw5
==10035== 
==10035== ---Thread-Announcement------------------------------------------
==10035== 
==10035== Thread #3 was created
==10035==    at 0x538987E: clone (clone.S:71)
==10035==    by 0x5050EC4: create_thread (createthread.c:100)
==10035==    by 0x5050EC4: pthread_create@@GLIBC_2.2.5 (pthread_create.c:797)
==10035==    by 0x4C36A27: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==10035==    by 0x1088BD: main (Hw5.c:28)
==10035== 
==10035== ----------------------------------------------------------------
==10035== 
==10035== Thread #3: lock order "0x309080 before 0x3090C0" violated
==10035== 
==10035== Observed (incorrect) order is: acquisition of lock at 0x3090C0
==10035==    at 0x4C3403C: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==10035==    by 0x10882E: worker (Hw5.c:16)
==10035==    by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==10035==    by 0x50506DA: start_thread (pthread_create.c:463)
==10035==    by 0x538988E: clone (clone.S:95)
==10035== 
==10035==  followed by a later acquisition of lock at 0x309080
==10035==    at 0x4C3403C: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==10035==    by 0x10883A: worker (Hw5.c:17)
==10035==    by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==10035==    by 0x50506DA: start_thread (pthread_create.c:463)
==10035==    by 0x538988E: clone (clone.S:95)
==10035== 
==10035== Required order was established by acquisition of lock at 0x309080
==10035==    at 0x4C3403C: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==10035==    by 0x108814: worker (Hw5.c:13)
==10035==    by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==10035==    by 0x50506DA: start_thread (pthread_create.c:463)
==10035==    by 0x538988E: clone (clone.S:95)
==10035== 
==10035==  followed by a later acquisition of lock at 0x3090C0
==10035==    at 0x4C3403C: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==10035==    by 0x108820: worker (Hw5.c:14)
==10035==    by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==10035==    by 0x50506DA: start_thread (pthread_create.c:463)
==10035==    by 0x538988E: clone (clone.S:95)
==10035== 
==10035==  Lock at 0x309080 was first observed
==10035==    at 0x4C3403C: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==10035==    by 0x108814: worker (Hw5.c:13)
==10035==    by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==10035==    by 0x50506DA: start_thread (pthread_create.c:463)
==10035==    by 0x538988E: clone (clone.S:95)
==10035==  Address 0x309080 is 0 bytes inside data symbol "m1"
==10035== 
==10035==  Lock at 0x3090C0 was first observed
==10035==    at 0x4C3403C: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==10035==    by 0x108820: worker (Hw5.c:14)
==10035==    by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==10035==    by 0x50506DA: start_thread (pthread_create.c:463)
==10035==    by 0x538988E: clone (clone.S:95)
==10035==  Address 0x3090c0 is 0 bytes inside data symbol "m2"
==10035== 
==10035== 
==10035== 
==10035== For counts of detected and suppressed errors, rerun with: -v
==10035== Use --history-level=approx or =none to gain increased speed, at
==10035== the cost of reduced accuracy of conflicting-access information
==10035== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 7 from 7)

我想外锁g不允许两个线程同时进入临界区。
只有一个线程可以获取锁 g在给定的时间。所以我认为不可能出现僵局。我穿了吗?为什么 helgrind 会抛出这个错误?请解释。

最佳答案

Helgrind 提示您的线程被观察到锁定互斥锁 m1m2在不同的相对顺序中,这也可以从代码的检查中清楚地看出。 Helgrind 会在获取顺序中查找并标记此类差异,因为一般而言,它们会产生死锁风险。

I think the outer lock g will not allow two threads to enter the critical section at same time. Only one thread can acquire the lock g at a given time. So I think there is no possibility for a deadlock. Am I worng?



你没有错。所呈现的特定程序不会死锁,因为每个线程都必须获取 g在它可以获取其他互斥锁之前。

Why helgrind is throwing this error?



因为 helgrind's 是对程序在一次运行期间的运行时行为的启发式分析。它并不假设程序的单次运行展示了所有可能的行为。另一方面,您的评估基于源代码分析。

您在这里看到的启发式规则是,任何线程都不应该以不同的相对顺序获取互斥对。对于您的特定程序,这会产生误报,但您的程序似乎是专门为产生这种情况而设计的。不需要互斥锁 m1m2首先如果互斥锁g将始终在获得其他任何一个时持有。如果任何其他线程可以获取 m1m2不持有g ,但是,那么死锁风险将是真实的,无论所述其他线程中的获取顺序如何。

无论如何,警告都表明您的代码存在真正的问题:要么您正在执行不需要的互斥操作,要么您确实存在当前或 future 的死锁风险。

关于c - 为什么 Helgrind 显示 "lock order violated"错误消息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62001623/

相关文章:

c - 函数中的 malloc 变量会发生什么?

c++ - 意外的位移结果

c - Winsock C TCP 套接字

java - 在 ThreadPoolExecutor 中设置 allowCoreThreadTimeOut() 是一个好习惯吗?

c - C 中的线程加工错误?

c - Pthread 屏障和树莓派

c - pthread_join() 不工作

将数组的指针更改为更大的数组

java - volatile 关键字原子性

C++:将结构传递给 PThread