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

ter*_*ry 63 c linux multithreading mutex pthreads

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

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

caf*_*caf 107

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

在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)
Run Code Online (Sandbox Code Playgroud)

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

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

  • @caf,你可以添加到你的答案,现在在gdb中有`thread find`命令.因此,在发现`mutex .__ data .__ owner`为22025之后,你可以运行:`thread find 22025`并获取gdb中线程的编号:(例如:`Thread 29 has target id'Thread 0x7fffdf5fe700(LWP 22025)'` ).所以你可以接下来用命令切换到持有锁的线程:`thread 29`或者只是`t 29` (8认同)
  • @Duck:`.__ data .__ owner`中的值是TID.当每个线程启动时,你可以让它们记录它们的TID(使用`tid = syscall(SYS_gettid);`)以及它们的`pthread_t`(来自`pthread_self()`). (5认同)
  • BTW:可以使用`info threads`将TID(`.__ data .__ owner`)映射到pthread ID(在gdb中运行的ID). (2认同)

Duc*_*uck 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);
}
Run Code Online (Sandbox Code Playgroud)

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

  • 记录的可能问题是它可能会破坏时间并使问题消失. (7认同)