Visualizzazione di una sezione critica
Le sezioni critiche possono essere visualizzate in modalità utente da diversi metodi. Il significato esatto di ogni campo dipende dalla versione di Microsoft Windows in uso.
Visualizzazione di sezioni critiche
Le sezioni critiche possono essere visualizzate dall'estensione !ntsdexts.locks , dall'estensione !critsec , dall'estensione !cs e dal comando dt (Tipo di visualizzazione).
L'estensione !ntsdexts.locks visualizza un elenco di sezioni critiche associate al processo corrente. Se viene usata l'opzione -v , vengono visualizzate tutte le sezioni critiche. Esempio:
0:000> !locks
CritSec ntdll!FastPebLock+0 at 77FC49E0
LockCount 0
RecursionCount 1
OwningThread c78
EntryCount 0
ContentionCount 0
*** Locked
....
Scanned 37 critical sections
Se si conosce l'indirizzo della sezione critica da visualizzare, è possibile usare l'estensione !critsec . Viene visualizzata la stessa raccolta di informazioni di !ntsdexts.locks. Ad esempio:
0:000> !critsec 77fc49e0
CritSec ntdll!FastPebLock+0 at 77FC49E0
LockCount 0
RecursionCount 1
OwningThread c78
EntryCount 0
ContentionCount 0
*** Locked
L'estensione !cs può visualizzare una sezione critica in base al relativo indirizzo, cercare un intervallo di indirizzi per le sezioni critiche e anche visualizzare la traccia dello stack associata a ogni sezione critica. Alcune di queste funzionalità richiedono il corretto funzionamento dei simboli di Windows completi. Se Application Verifier è attivo, !cs -t può essere usato per visualizzare l'albero delle sezioni critiche. Per informazioni dettagliate ed esempi, vedere la pagina di riferimento !cs .
Le informazioni visualizzate da !cs sono leggermente diverse rispetto a quelle visualizzate da !ntsdexts.locks e !critsec. Ad esempio:
## 0:000> !cs 77fc49e0
Critical section = 0x77fc49e0 (ntdll!FastPebLock+0x0)
DebugInfo = 0x77fc3e00
LOCKED
LockCount = 0x0
OwningThread = 0x00000c78
RecursionCount = 0x1
LockSemaphore = 0x0
SpinCount = 0x00000000
Il comando dt (Tipo di visualizzazione) può essere usato per visualizzare il contenuto letterale della struttura RTL_CRITICAL_SECTION. Ad esempio:
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
Interpretazione dei campi della sezione critica in Windows XP e Windows 2000
I campi più importanti della struttura di sezione critica sono i seguenti:
In Microsoft Windows 2000 e Windows XP, il campo LockCount indica il numero di volte in cui qualsiasi thread ha chiamato la routine EnterCriticalSection per questa sezione critica, meno una. Questo campo inizia a -1 per una sezione critica sbloccata. Ogni chiamata di EnterCriticalSection incrementa questo valore; ogni chiamata di LeaveCriticalSection lo decrementa . Ad esempio, se LockCount è 5, questa sezione critica è bloccata, un thread lo ha acquisito e cinque thread aggiuntivi sono in attesa di questo blocco.
Il campo RecursionCount indica il numero di volte in cui il thread proprietario ha chiamato EnterCriticalSection per questa sezione critica.
Il campo EntryCount indica il numero di volte in cui un thread diverso dal thread proprietario ha chiamato EnterCriticalSection per questa sezione critica.
Una sezione critica appena inizializzata è simile alla seguente:
0:000> !critsec 433e60
CritSec mymodule!cs+0 at 00433E60
LockCount NOT LOCKED
RecursionCount 0
OwningThread 0
EntryCount 0
ContentionCount 0
Il debugger visualizza "NOT LOCKED" come valore per LockCount. Il valore effettivo di questo campo per una sezione critica sbloccata è -1. È possibile verificare questa operazione con il comando dt (Tipo di visualizzazione):
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
Quando il primo thread chiama la routine EnterCriticalSection, i campi LockCount della sezione critica, RecursionCount, EntryCount e ContentionCount vengono tutti incrementati di uno e OwningThread diventa l'ID thread del chiamante. EntryCount e ContentionCount non vengono mai decrementati. Ad esempio:
0:000> !critsec 433e60
CritSec mymodule!cs+0 at 00433E60
LockCount 0
RecursionCount 1
OwningThread 4d0
EntryCount 0
ContentionCount 0
A questo punto, quattro cose diverse possono accadere.
Il thread proprietario chiama di nuovo EnterCriticalSection . Questo incrementerà LockCount e RecursionCount. EntryCount non viene incrementato.
0:000> !critsec 433e60 CritSec mymodule!cs+0 at 00433E60 LockCount 1 RecursionCount 2 OwningThread 4d0 EntryCount 0 ContentionCount 0
Un thread diverso chiama EnterCriticalSection. Verrà incrementato LockCount e EntryCount. La ricorsioneCount non viene incrementata.
0:000> !critsec 433e60 CritSec mymodule!cs+0 at 00433E60 LockCount 1 RecursionCount 1 OwningThread 4d0 EntryCount 1 ContentionCount 1
Il thread proprietario chiama LeaveCriticalSection. Questo decrementerà LockCount (a -1) e RecursionCount (a 0) e verrà reimpostato OwningThread su 0.
0:000> !critsec 433e60 CritSec mymodule!cs+0 at 00433E60 LockCount NOT LOCKED RecursionCount 0 OwningThread 0 EntryCount 0 ContentionCount 0
Un altro thread chiama LeaveCriticalSection. Questo produce gli stessi risultati del thread proprietario che chiama LeaveCriticalSection - decrementerà LockCount (a -1) e RecursionCount (a 0) e verrà reimpostato OwningThread su 0.
Quando qualsiasi thread chiama LeaveCriticalSection, Windows decrements LockCount e RecursionCount. Questa funzionalità presenta aspetti sia buoni che cattivi. Consente a un driver di dispositivo di immettere una sezione critica su un thread e lasciare la sezione critica su un altro thread. Tuttavia, consente anche di chiamare accidentalmente LeaveCriticalSection nel thread errato o di chiamare LeaveCriticalSection troppo volte e causare il raggiungimento di valori inferiori a -1. Ciò causa il danneggiamento della sezione critica e causa l'attesa indefinita di tutti i thread nella sezione critica.
Interpretazione dei campi della sezione critica in Windows Server 2003 SP1 e versioni successive
In Microsoft Windows Server 2003 Service Pack 1 e versioni successive di Windows, il campo LockCount viene analizzato come segue:
Il bit più basso mostra lo stato del blocco. Se questo bit è 0, la sezione critica è bloccata; se è 1, la sezione critica non è bloccata.
Il bit successivo mostra se un thread è stato interrotto per questo blocco. Se questo bit è 0, un thread è stato interrotto per questo blocco; se è 1, nessun thread è stato interrotto.
I bit rimanenti sono il complemento del numero di thread in attesa del blocco.
Si supponga, ad esempio, che LockCount sia -22. Il bit più basso può essere determinato in questo modo:
0:009> ? 0x1 & (-0n22)
Evaluate expression: 0 = 00000000
Il bit più basso può essere determinato in questo modo:
0:009> ? (0x2 & (-0n22)) >> 1
Evaluate expression: 1 = 00000001
I componenti aggiuntivi dei bit rimanenti possono essere determinati in questo modo:
0:009> ? ((-1) - (-0n22)) >> 2
Evaluate expression: 5 = 00000005
In questo esempio il primo bit è 0 e quindi la sezione critica è bloccata. Il secondo bit è 1 e quindi non è stato interrotto alcun thread per questo blocco. Il complemento dei bit rimanenti è 5 e quindi ci sono cinque thread in attesa di questo blocco.
Informazioni aggiuntive
Per informazioni su come eseguire il debug dei timeout della sezione critica, vedere Timeout della sezione critica. Per informazioni generali sulle sezioni critiche, vedere la Microsoft Windows SDK, Windows Driver Kit (WDK) o Microsoft Windows Internals di Mark Russinovich e David Solomon.