zoukankan      html  css  js  c++  java
  • 利用glibc中锁结构的信息解决死锁问题

       首先非常感谢老丁和老李同学的帮助,没有他们这个问题估计又得搞很久。遇见这个问题,真是头疼。不熟悉代码、不熟悉流程,但是领导还是把活给排下来了(实在不解),只能硬着头皮找了。
    问题是这样的,cache服务器中有一个存储对象的哈希表,每次访问哈希表时都要获取hash_rwlock读写锁,现在进程在获取读锁时死锁。使用gdb进入3个worker进程,发现死锁的位置都一样,都是在获取hash_rwlock读锁时阻塞住了。遇见这样的问题,加上对代码不熟,真是各种犯二。因为reload的关系,进程其实总共有9个,但是3个是一组的,所以只看了其中的一组,没有全部查看,如果全部查看的话,估计可以更早发现问题。
    在同事的提醒下,先在阻塞的位置打印锁的结构,如下所示:

    找了glibc的源码来看,发现pthread_rwlock_t结构的成员竟然完全没有注释,只好去看加锁、解锁的函数。在获取读锁时,只有在__writer成员为0并且__nr_writers_queued为0,即没有进程获取写锁或等待获取写锁时,才会获取锁成功。获取读锁成功后,会将__nr_readers成员加1.这么看来的话,__nr_readers存储的是当前获取读锁的进程或线程数量。在获取写锁时,只有在__writer成员为0,并且__nr_readers为0,即没有进程或线程获取写锁或读锁时,才会获取写锁成功。获取写锁成功后,会将__writer成员设置为线程ID(如果是单进程,则为进程ID),如下所示:
    rwlock->__data.__writer = THREAD_GETMEM (THREAD_SELF, tid);
    最初没有注意到这行代码,自己写了一个获取写锁的测试程序,然后用gdb打印出来的。这个方法虽然笨,没有思路的时候或许着急的时候,也是不错的。
    有了这些信息,再看上面的图,可以发现很多信息。__nr_readers为0,表示没有进程或线程获取hash_rwlock的读锁;__writer为12959,说明进程ID为12959的进程正在获取hash_rwlock的写锁。
    现在一下子找到了方向,立马gdb进入12959进程,发现它阻塞在获取另一个进程锁process_lock(类型为pthread_mutex_t),打印process_lock,如下图所示:
       pthread_mutex_t类型中的__owner中存储的是获取当前互斥锁的进程或线程ID。找到了互斥锁的持有者,再gdb进入12960进程,发现阻塞在获取hash_rwlock读锁的位置。
    至此问题就很明了了,典型的死锁。A进程获取了锁m,然后去获取另一个锁n,而B进程获取了锁n,然后去获取了另一个锁m,交叉去获取锁,都阻塞了,都在等对方释放锁。出现这种问题的原因,要么是流程设计有问题,要么就是在某个地方获取锁了之后没有正确释放。我们的这个问题就属于后者,在一个函数中在失败的时候没有释放锁就直接返回了......

  • 相关阅读:
    PAT 1006 Sign In and Sign Out
    PAT 1004. Counting Leaves
    JavaEE开发环境安装
    NoSql数据库探讨
    maven的配置
    VMWARE 下使用 32位 Ubuntu Linux ,不能给它分配超过3.5G 内存?
    XCODE 4.3 WITH NO GCC?
    在苹果虚拟机上跑 ROR —— Ruby on Rails On Vmware OSX 10.7.3
    推荐一首让人疯狂的好歌《Pumped Up Kicks》。好吧,顺便测下博客园可以写点无关技术的帖子吗?
    RUBY元编程学习之”编写你的第一种领域专属语言“
  • 原文地址:https://www.cnblogs.com/aukle/p/3221856.html
Copyright © 2011-2022 走看看