一处死锁分析
最近在进行回归测试的时候,QA同学反映有一处死锁,导致大量线程Hang死。通过pstack
查看后,发现如下可疑的两个线程:
1 2 3 |
Thread 1: 1. Hold A.ReadLock, 2. Request B.ReadLock Thread 2: 1. Hold B.ReadLock, 2. Request A.WriteLock |
看到此处就觉得比较奇怪,Thread2被Hang住很正常,因为A的读锁被Thread1占有了,此时无法加上A的写锁,但是为什么Thread 1会被锁死呢?因为此时B的读锁最少被Thread 2加上了,说明没有写线程占有写锁。且其他大量线程都被锁死在请求B的读锁的时候。
排除掉所有那些请求B的读锁被Hang死的线程后,发现了一个可疑的线程,这个线程Hang在如下位置
1 2 |
Thread 3: Request B.WriteLock |
即存在一个线程在请求B的写锁,且处于等待的过程中。疑点比较明显,于是gdb
之后,打印了一下这个pthread_rwlock_t
的属性,发现其__rw_kind
的属性值是1,顺藤摸瓜,发现这个读写锁在初始化的时候使用了如下过程:
1 2 3 4 5 |
pthread_rwlockattr_t attr; pthread_rwlockattr_init(&attr) pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); pthread_rwlock_init(&_rwlock, &attr); |
其中PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
表明写锁优先的模式,即有写者等待时,所有读者被阻塞,所以因为Thread 3在获取B的写锁,则Thread 1无法获取B的读锁,从而导致A的读锁不会被释放,此种情况Thread 2无法获取A的写锁,也不会释放B的读锁,导致死锁。
解完Bug后,大呼原来多线程情况下,两个以前线程也有可能在某些情况下造成死锁。即只要有加锁顺序不一致的情况,且有读写锁混合的情况下,如果有写锁优先的情况,也有可能导致死锁。
换了Disqus,试一下。