Anzeigen eines kritischen Abschnitts
Kritische Abschnitte können im Benutzermodus mit verschiedenen Methoden angezeigt werden. Die genaue Bedeutung der einzelnen Felder hängt von der Version der microsoft Windows-Version ab, die Sie verwenden.
Anzeigen kritischer Abschnitte
Kritische Abschnitte können durch die Erweiterung !ntsdexts.locks , die Erweiterung !critsec , die Erweiterung !cs und den Befehl dt (Anzeigetyp) angezeigt werden.
Die Erweiterung !ntsdexts.locks zeigt eine Liste der kritischen Abschnitte an, die dem aktuellen Prozess zugeordnet sind. Wenn die Option -v verwendet wird, werden alle wichtigen Abschnitte angezeigt. Beispiel:
0:000> !locks
CritSec ntdll!FastPebLock+0 at 77FC49E0
LockCount 0
RecursionCount 1
OwningThread c78
EntryCount 0
ContentionCount 0
*** Locked
....
Scanned 37 critical sections
Wenn Sie die Adresse des kritischen Abschnitts kennen, den Sie anzeigen möchten, können Sie die Erweiterung !critsec verwenden. Dadurch wird dieselbe Sammlung von Informationen wie !ntsdexts.locks angezeigt. Beispiel:
0:000> !critsec 77fc49e0
CritSec ntdll!FastPebLock+0 at 77FC49E0
LockCount 0
RecursionCount 1
OwningThread c78
EntryCount 0
ContentionCount 0
*** Locked
Die Erweiterung !cs kann einen kritischen Abschnitt basierend auf seiner Adresse anzeigen, einen Adressbereich nach kritischen Abschnitten durchsuchen und sogar die stapelbasierte Ablaufverfolgung anzeigen, die jedem kritischen Abschnitt zugeordnet ist. Einige dieser Features erfordern vollständige Windows-Symbole, um ordnungsgemäß zu funktionieren. Wenn application verifier aktiv ist, kann !cs -t verwendet werden, um die Struktur des kritischen Abschnitts anzuzeigen. Details und Beispiele finden Sie auf der !cs-Referenzseite .
Die von !cs angezeigten Informationen unterscheiden sich geringfügig von denen von !ntsdexts.locks und !critsec. Beispiel:
## 0:000> !cs 77fc49e0
Critical section = 0x77fc49e0 (ntdll!FastPebLock+0x0)
DebugInfo = 0x77fc3e00
LOCKED
LockCount = 0x0
OwningThread = 0x00000c78
RecursionCount = 0x1
LockSemaphore = 0x0
SpinCount = 0x00000000
Der Befehl dt (Anzeigetyp) kann verwendet werden, um den Literalinhalt der RTL_CRITICAL_SECTION-Struktur anzuzeigen. Beispiel:
0:000> dt RTL_CRITICAL_SECTION 77fc49e0
+0x000 DebugInfo : 0x77fc3e00
+0x004 LockCount : 0
+0x008 RecursionCount : 1
+0x00c OwningThread : 0x00000c78
+0x010 LockSemaphore : (null)
+0x014 SpinCount : 0
Interpretieren kritischer Abschnittsfelder in Windows XP und Windows 2000
Die wichtigsten Felder der Kritischen Abschnittsstruktur sind wie folgt:
In Microsoft Windows 2000 und Windows XP gibt das Feld LockCount an, wie oft ein Thread die EnterCriticalSection-Routine für diesen kritischen Abschnitt aufgerufen hat, abzüglich 1. Dieses Feld beginnt bei -1 für einen entsperrten kritischen Abschnitt. Jeder Aufruf von EnterCriticalSection erhöht diesen Wert; jeder Aufruf von LeaveCriticalSection erhöht ihn. Wenn LockCount beispielsweise 5 ist, ist dieser kritische Abschnitt gesperrt, ein Thread hat ihn abgerufen, und fünf weitere Threads warten auf diese Sperre.
Das Feld RecursionCount gibt an, wie oft der besitzende Thread EnterCriticalSection für diesen kritischen Abschnitt aufgerufen hat.
Das Feld EntryCount gibt an, wie oft ein anderer Thread als der besitzende Thread EnterCriticalSection für diesen kritischen Abschnitt aufgerufen hat.
Ein neu initialisierter kritischer Abschnitt sieht wie folgt aus:
0:000> !critsec 433e60
CritSec mymodule!cs+0 at 00433E60
LockCount NOT LOCKED
RecursionCount 0
OwningThread 0
EntryCount 0
ContentionCount 0
Der Debugger zeigt "NOT LOCKED" als Wert für LockCount an. Der tatsächliche Wert dieses Felds für einen entsperrten kritischen Abschnitt ist -1. Sie können dies mit dem Befehl dt (Anzeigetyp) überprüfen:
0:000> dt RTL_CRITICAL_SECTION 433e60
+0x000 DebugInfo : 0x77fcec80
+0x004 LockCount : -1
+0x008 RecursionCount : 0
+0x00c OwningThread : (null)
+0x010 LockSemaphore : (null)
+0x014 SpinCount : 0
Wenn der erste Thread die EnterCriticalSection-Routine aufruft , werden die Felder LockCount, RecursionCount, EntryCount und ContentionCount des kritischen Abschnitts um eins erhöht, und OwningThread wird zur Thread-ID des Aufrufers. EntryCount und ContentionCount werden nie dekrementiert. Beispiel:
0:000> !critsec 433e60
CritSec mymodule!cs+0 at 00433E60
LockCount 0
RecursionCount 1
OwningThread 4d0
EntryCount 0
ContentionCount 0
An diesem Punkt können vier verschiedene Dinge passieren.
Der besitzereigene Thread ruft EnterCriticalSection erneut auf. Dadurch werden LockCount und RecursionCount inkrementiert. EntryCount wird nicht erhöht.
0:000> !critsec 433e60 CritSec mymodule!cs+0 at 00433E60 LockCount 1 RecursionCount 2 OwningThread 4d0 EntryCount 0 ContentionCount 0
Ein anderer Thread ruft EnterCriticalSection auf. Dadurch werden LockCount und EntryCount erhöht. RecursionCount wird nicht erhöht.
0:000> !critsec 433e60 CritSec mymodule!cs+0 at 00433E60 LockCount 1 RecursionCount 1 OwningThread 4d0 EntryCount 1 ContentionCount 1
Der besitzereigene Thread ruft LeaveCriticalSection auf. Dadurch werden LockCount (auf -1) und RecursionCount (auf 0) verringert und OwningThread auf 0 zurückgesetzt.
0:000> !critsec 433e60 CritSec mymodule!cs+0 at 00433E60 LockCount NOT LOCKED RecursionCount 0 OwningThread 0 EntryCount 0 ContentionCount 0
Ein anderer Thread ruft LeaveCriticalSection auf. Dies führt zu den gleichen Ergebnissen wie der Besitzerthread , der LeaveCriticalSection aufruft . Dadurch wird LockCount (auf -1) und RecursionCount (auf 0) verringert und OwningThread auf 0 zurückgesetzt.
Wenn ein Thread LeaveCriticalSection aufruft, verringert Windows LockCount und RecursionCount. Dieses Feature hat sowohl gute als auch schlechte Aspekte. Es ermöglicht einem Gerätetreiber, einen kritischen Abschnitt in einem Thread einzugeben und den kritischen Abschnitt in einem anderen Thread zu belassen. Es ermöglicht jedoch auch, LeaveCriticalSection versehentlich im falschen Thread aufzurufen, oder LeaveCriticalSection zu oft aufzurufen und dazu zu führen, dass LockCount Werte unter -1 erreicht. Dies beschädigt den kritischen Abschnitt und bewirkt, dass alle Threads unbegrenzt auf den kritischen Abschnitt warten.
Interpretieren kritischer Abschnittsfelder in Windows Server 2003 SP1 und höher
In Microsoft Windows Server 2003 Service Pack 1 und höheren Versionen von Windows wird das Feld LockCount wie folgt analysiert:
Das niedrigste Bit zeigt die Sperre status an. Wenn dieses Bit 0 ist, ist der kritische Abschnitt gesperrt. wenn es 1 ist, ist der kritische Abschnitt nicht gesperrt.
Das nächste Bit zeigt an, ob ein Thread für diese Sperre geweckt wurde. Wenn dieses Bit 0 ist, wurde ein Thread für diese Sperre geweckt. wenn es 1 ist, wurde kein Thread geweckt.
Die verbleibenden Bits sind das Eins-Komplement der Anzahl von Threads, die auf die Sperre warten.
Angenommen, der LockCount ist -22. Das niedrigste Bit kann auf folgende Weise bestimmt werden:
0:009> ? 0x1 & (-0n22)
Evaluate expression: 0 = 00000000
Das nächstniedrige Bit kann auf folgende Weise bestimmt werden:
0:009> ? (0x2 & (-0n22)) >> 1
Evaluate expression: 1 = 00000001
Das Eins-Komplement der verbleibenden Bits kann auf folgende Weise bestimmt werden:
0:009> ? ((-1) - (-0n22)) >> 2
Evaluate expression: 5 = 00000005
In diesem Beispiel ist das erste Bit 0 und daher der kritische Abschnitt gesperrt. Das zweite Bit ist 1, und daher wurde kein Thread für diese Sperre geweckt. Das Komplement der verbleibenden Bits ist 5, sodass fünf Threads auf diese Sperre warten.
Weitere Informationen
Informationen zum Debuggen kritischer Abschnitttimeouts finden Sie unter Timeouts für kritische Abschnitte. Allgemeine Informationen zu wichtigen Abschnitten finden Sie unter Microsoft Windows SDK, Windows Driver Kit (WDK) oder Microsoft Windows Internals von Mark Russinovich und David Solomon.