RELEASE版本下PTHREAD_MUTEX_T死锁分析

  debug 版本的应用程序发生死锁,可以将pthread_mutex_t打印出来,查看其中的owner字段即可知道锁被哪个线程持有,从而进一步分析死锁原因。
release版本的程序,由于进行了优化,可能无法直接打出锁变量。 这里介绍一个简单方法,可以查看release版(当然也支持debug)的锁状态,以便快速定位死锁问题。
操作步骤
1)    gdb  attach  到死锁的进程.
例如  gdb  –p  2456
2)    thread 命令切换到等待锁(这里主要指Mutex,暂不考虑读写锁)的某个线程。 可以结合 info thr、thr apply all bt 等命令确定哪些线程在等锁。
3)    bt 查看该线程堆栈
(gdb) bt
#0  0x00110424 in __kernel_vsyscall ()
#1  0x0062d019 in __lll_lock_wait () from /lib/libpthread.so.0
#2  0x00628430 in _L_lock_677 () from /lib/libpthread.so.0
#3  0x00628301 in pthread_mutex_lock () from /lib/libpthread.so.0
#4  0x080870cc in Dahua::Infra::CMutex::enter (this=0xbffff378) at Src/Infra3/Mutex.cpp:99
#5  0x0804eb6d in Dahua::EFS::CDatanodeOMClient::close (this=0xbffff36c) at DatanodeOMClient.cpp:165
4)    frame  1  切换到  __lll_lock_wait () 帧
5)    执行 p *(pthread_mutex_t*)$ebx
$1 = {__data = {__lock = 2, __count = 0, __owner = 20644, __kind = 0, __nusers = 1, {__spins = 0, __list = {
        __next = 0x0}}},
  __size = "\002\000\000\000\000\000\000\000\244P\000\000\000\000\000\000\001\000\000\000\000\000\000", __align = 2}
Owner 字段表示是哪个线程持有这把锁,它是线程的 LWP 号,可以通过 info thr 查看。
6)     根据info thr 的信息,thr 命令切换到 owner对应的线程,结合代码排查。 一般来说,这个线程应该也在等锁,重复执行 4、5 步骤,可以看到它锁等待的锁被谁持有。 再结合代码分析,基本上可以定位出死锁位置。
注意事项
1)    上述方法只适用于32bit系统上使用 pthread_mutex_t 造成的死锁。 X86_64 位系统上,对应的寄存器貌似是 rdi ,也就是说命令应该改成
p *(pthread_mutex_t*)$rdi
2) 读写锁造成的死锁,需要结合glibc源码和汇编,找出pthread_rwlock_t的地址(具体是啥还有待分析 ^_^),将其打印出来应该即可。
3)如果owner对应的线程已经退出,就无法通过gdb查看该线程的堆栈。 因此建议在日志中打印线程的LWP号(可通过getttid打印),找到该线程的日志信息,分析是哪个线程造成的死锁。
#define gettid() syscall(__NR_gettid)
4)如果提示 pthread_mutex_t 符号找不到,说明gdb没有为 pthreadtypes.h 加载符号表,这种情况下仍有方法查看锁状态:
(gdb) print *((int*)($ebx))      // lock 字段
$4 = 2
(gdb) print *((int*)($ebx)+1)    // count 字段
$5 = 0
(gdb) print *((int*)($ebx)+2)    // owner字段
$6 = 12275
附:pthread_mutex_t 定义
typedef union
{
  struct __pthread_mutex_s
  {
    int __lock;
    unsigned int __count;
    int __owner;
    /* KIND must stay at this position in the structure to maintain
       binary compatibility.  */
    int __kind;
    unsigned int __nusers;
    __extension__ union
    {
      int __spins;
      __pthread_slist_t __list;
    };
  } __data;
  char __size[__SIZEOF_PTHREAD_MUTEX_T];
  long int __align;
} pthread_mutex_t;

你可能感兴趣的:(RELEASE版本下PTHREAD_MUTEX_T死锁分析)