是否可以确定持有互斥锁的线程?

时间:2010-08-14 11:38:25

标签: c linux multithreading pthreads mutex

首先,我使用pthread库编写多线程C程序。线程总是被等待的互斥锁挂起。当我使用strace实用程序查找线程处于FUTEX_WAIT状态时,我想知道当时哪个线程持有该互斥锁。但我不知道怎么能做到。有没有公​​用事业可以做到这一点?

有人告诉我Java虚拟机支持这个,所以我想知道Linux是否支持这个功能。

4 个答案:

答案 0 :(得分:97)

您可以使用互斥锁内部的知识来执行此操作。通常这不是一个好主意,但调试很好。

在Linux下使用pthreads的NPTL实现(任何现代的glibc),你可以检查__data.__owner结构的pthread_mutex_t成员,找出当前锁定它的线程。这是在使用gdb附加到流程后如何执行此操作:

(gdb) thread 2
[Switching to thread 2 (Thread 0xb6d94b90 (LWP 22026))]#0  0xb771f424 in __kernel_vsyscall ()
(gdb) bt
#0  0xb771f424 in __kernel_vsyscall ()
#1  0xb76fec99 in __lll_lock_wait () from /lib/i686/cmov/libpthread.so.0
#2  0xb76fa0c4 in _L_lock_89 () from /lib/i686/cmov/libpthread.so.0
#3  0xb76f99f2 in pthread_mutex_lock () from /lib/i686/cmov/libpthread.so.0
#4  0x080484a6 in thread (x=0x0) at mutex_owner.c:8
#5  0xb76f84c0 in start_thread () from /lib/i686/cmov/libpthread.so.0
#6  0xb767784e in clone () from /lib/i686/cmov/libc.so.6
(gdb) up 4
#4  0x080484a6 in thread (x=0x0) at mutex_owner.c:8
8               pthread_mutex_lock(&mutex);
(gdb) print mutex.__data.__owner
$1 = 22025
(gdb)

(我切换到挂起的线程;执行回溯以找到它被卡住的pthread_mutex_lock();更改堆栈帧以找出它试图锁定的互斥锁的名称;然后打印该互斥锁的所有者)。这告诉我LWP ID 22025的线程是罪魁祸首。

然后,您可以使用thread find 22025查找该线程的gdb线程号并切换到该线程。

答案 1 :(得分:5)

我不知道有任何这样的设施,所以我认为你不会那么容易 - 并且它可能不像你想的那样提供有助于调试程序的信息。由于技术看起来很低,日志记录是你调试这些东西的朋友。开始收集您自己的小日志功能。他们不必花哨,他们只需要在调试时完成工作。

抱歉C ++,但是:

void logit(const bool aquired, const char* lockname, const int linenum)
{
    pthread_mutex_lock(&log_mutex);

    if (! aquired)
        logfile << pthread_self() << " tries lock " << lockname << " at " << linenum << endl;
    else
        logfile << pthread_self() << " has lock "   << lockname << " at " << linenum << endl;

    pthread_mutex_unlock(&log_mutex);
}


void someTask()
{
    logit(false, "some_mutex", __LINE__);

    pthread_mutex_lock(&some_mutex);

    logit(true, "some_mutex", __LINE__);

    // do stuff ...

    pthread_mutex_unlock(&some_mutex);
}

记录不是一个完美的解决方案,但没有。它通常可以为您提供您需要知道的信息。

答案 2 :(得分:2)

通常,libc / platforms调用由OS抽象层抽象。可以使用所有者变量和pthread_mutex_timedlock跟踪互斥锁死锁。每当线程锁定它时,它应该使用自己的tid(gettid()更新变量,并且还可以为pthread id存储提供另一个变量)。因此,当其他线程在pthread_mutex_timedlock上阻塞并超时时,它可以打印所有者tid和pthread_id的值。通过这种方式,您可以轻松找到所有者主题。请找到下面的代码段,请注意不处理所有错误条件

pid_t ownerTid;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

class TimedMutex {
    public:
        TimedMutex()
        {
           struct timespec abs_time;

           while(1)
           {
               clock_gettime(CLOCK_MONOTONIC, &abs_time);
               abs_time.tv_sec += 10;
               if(pthread_mutex_timedlock(&mutex,&abs_time) == ETIMEDOUT)
               {
                   log("Lock held by thread=%d for more than 10 secs",ownerTid);
                   continue;
               }
               ownerTid = gettid();
           }
        }

        ~TimedMutex()
        {

             pthread_mutex_unlock(&mutex);  
        }
};

还有其他方法可以找出死锁,也许这个链接可能对http://yusufonlinux.blogspot.in/2010/11/debugging-core-using-gdb.html有帮助。

答案 3 :(得分:1)

请阅读以下链接,这是一个寻找锁所有者的通用解决方案。即使锁定在库的一侧并且您没有源代码也可以工作。

https://en.wikibooks.org/wiki/Linux_Applications_Debugging_Techniques/Deadlocks