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.

  1. 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
    
  2. 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
    
  3. 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
    
  4. 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.