2012-10-25 9 views
6

Ich habe eine Klasseninstanz, die von mehreren anderen Klassen in anderen Threads zur Kommunikation verwendet wird.Was könnte einen Deadlock einer einzelnen Schreib/Mehrfachlesesperre verursachen?

Diese Klasse verwendet eine schlanke Leser/Schreiber-Sperre (WinAPI des SRWLOCK) als Synchronisationsobjekt und ein paar RAII Helferklassen tatsächlich zum Sperren/Entsperren der Sache:

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; 
}; 

Das Problem ist die ganze Sache Deadlocks die ganze Zeit. Wenn ich das verklemmte Programm anhalten, ich sehe:

  • ein Thread in AcquireSRWLockExclusive() stecken;
  • zwei Threads stecken in AcquireSRWLockShared();
  • readCounter global ist auf 3.

So wie ich es sehe, ist der einzige Weg dies geschehen ist CReadLock Instanz destructor irgendwie irgendwo genannt wurde nicht so die Sperre ständig hängen geblieben ist. Der einzige Weg dafür (soweit ich weiß) ist, dass eine Ausnahme ausgelöst wurde. Es war nicht. Ich überprüfte.

Was könnte das Problem sein? Wie soll ich dieses Ding reparieren (oder zumindest den Grund dafür finden)?

Antwort

9

Verwenden Sie Read Lock in rekursiver Weise?

void foo() 
{ 
    CReadLock rl(m_lock); 
    ... 
    bar(); 
} 
void bar() 
{ 
    CReadLock rl(m_lock); 
    ... 
} 
void baz() 
{ 
    CWritedLock rl(m_lock); 
    ... 
} 

wenn foo() und baz() genannt werden gleichzeitig können Sie Deadlock erhalten:

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 

Die Tatsache, dass Sie haben 2 Threads auf Read Schloss und Read-Lock-Zähler geklebt ist 3, die am ehesten zeigt, dass Sie eine Rekursion in einer der Sperren - dh ein Thread hatte versucht, die Lesesperre zweimal zu erfassen.

+0

Sollte nicht "bar" nur die Sperre bekommen? Es kann auch möglich sein, zu blockieren, wenn 'foo'' baz' aufruft (nicht wissen, ob Sperren rekursiv sind) – Lol4t0

+0

Nicht notwendig, Win32 API 'AcquireSRWLockShared' ist ** nicht rekursiv ** im Gegensatz zu POSIX' pthread_rwlock_rdlock' oder 'EnterCriticalSection' – Artyom

+0

Kannst du beweisen, dass 'baz bittet, Schreibsperre zu erstellen, werden jetzt alle Lesesperren blockiert, bis alle freigegeben sind - wartet.'? Weil MSDN [http://msdn.microsoft.com/en-us/library/windows/desktop/aa904937%28v=vs.85%29.aspx]: 'Es gibt keine Garantie über die Reihenfolge, in der Threads diese Anfrage Eigentum wird das Eigentum gewährt werden; SRW-Schlösser sind weder fair noch FIFO. – Lol4t0

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

Nun, soweit ich von ihr lesen können, Sie einen Thread haben derzeit das Lesesperre hält, wartet ein Schreib Faden für die Lesesperre freigegeben werden, und zwei Lese Fäden für diesen Schreib Thread wartet Holen und lösen Sie das Schloss.

Mit anderen Worten, Sie haben einen baumelnden Lese-Thread, der nicht zerstört wurde, wie Sie selbst sagen. Fügen Sie dem Destruktor und dem Konstruktor den Debug-Druck hinzu.

Verwandte Themen