2012-10-25 84 views
6

我有一个类实例被其他线程中的其他几个类用于通信。什么可能导致单个写/多读锁的死锁?

该类采用了超薄读/写器锁(WinAPI的的SRWLOCK)作为一个同步对象和一对夫妇RAII辅助类的实际锁定/解锁的事情:

static unsigned int readCounter = 0; 

class CReadLock 
{ 
public: 
    CReadLock(SRWLOCK& Lock) : m_Lock(Lock) { InterlockedIncrement(&readCounter); AcquireSRWLockShared(&m_Lock); } 
    ~CReadLock() {ReleaseSRWLockShared(m_Lock); InterlockedDecrement(&readCounter);} 

private: 
    SRWLOCK& m_Lock; 
}; 

class CWriteLock 
{ 
public: 
    CWriteLock(SRWLOCK& Lock) : m_Lock(Lock) { AcquireSRWLockExclusive(&m_Lock); } 
    ~CWriteLock() { ReleaseSRWLockExclusive(&m_Lock); } 

private: 
    SRWLOCK& m_Lock; 
}; 

的问题是整个事情的死锁每时每刻。当我暂停死锁程序时,我看到:

  • 单线卡在AcquireSRWLockExclusive();
  • 两个线程卡在AcquireSRWLockShared();
  • readCounter全球设置为3

我看到它的方式,要做到这一点的唯一方法是CReadLock实例的析构函数没有被调用莫名其妙的地方,因此锁是永久地。然而,发生这种情况的唯一方式(据我所知)是因为抛出了异常。事实并非如此。我检查了。

可能是什么问题?我应该如何解决这个问题(或者至少找出原因)?

回答

9

您是否以递归方式使用Read锁?

​​

如果foo()baz()同时叫你可能会死锁:

1. (Thread A) foo locks 
2. (Thread B) baz asks to create write lock now all read locks would block until all are released - waits. 
3. (Thread A) bar tries to lock and waits because there is pending write lock 

你已经被困在读锁和读锁定计数器2个线程的事实是3,最有可能表明你有在一个锁中递归 - 即一个线程试图获得读锁两次。

+0

不应该'酒吧'只是得到锁?如果'foo'调用'baz'(不知道锁是否是递归的),它也许可能会死锁 – Lol4t0

+0

不需要,Win32 API的'AcquireSRWLockShared' **不是递归**,不像POSIX的'pthread_rwlock_rdlock'或'EnterCriticalSection' – Artyom

+0

你能证明'baz要求创建写锁吗?现在所有的读锁都会被阻塞,直到所有的锁都被释放 - 等待。'?因为MSDN [说](http://msdn.microsoft.com/en-us/library/windows/desktop/aa904937%28v=vs.85%29.aspx):'不能保证线程的顺序该请求的所有权将被授予所有权; SRW锁定既不公平也不先进。' – Lol4t0

3
one thread stuck in AcquireSRWLockExclusive(); 
two threads stuck in AcquireSRWLockShared(); 
readCounter global is set to 3. 

嘛,据我可以从中读出,你有一个线程当前持有读锁,一个写线程等待读取锁被释放,并且两个读线程等待的写线程获得并释放锁定。

换句话说,你有一个悬空阅读线程,它没有被破坏,就像你自己说的那样。将调试打印添加到析构函数和构造函数。