Condividi tramite


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. Ecco un 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. Per 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 l'analisi dello stack associata a ogni sezione critica. Alcune di queste funzionalità richiedono il corretto funzionamento dei simboli di Windows completi. Se Application Verifier è attivo, è possibile usare !cs -t 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 da quelle visualizzate da !ntsdexts.locks e !critsec. Per 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. Per 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 da -1 per una sezione critica non bloccata. Ogni chiamata di EnterCriticalSection incrementa questo valore; ogni chiamata di LeaveCriticalSection la 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 verificarlo 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, RecursionCount, EntryCount e ContentionCount della sezione critica vengono incrementati di uno e OwningThread diventa l'ID thread del chiamante. EntryCount e ContentionCount non vengono mai decrementati. Per esempio:

0:000> !critsec 433e60
CritSec mymodule!cs+0 at 00433E60
LockCount          0
RecursionCount     1
OwningThread       4d0
EntryCount         0
ContentionCount    0

A questo punto, possono verificarsi quattro cose diverse.

  1. Il thread proprietario chiama nuovamente EnterCriticalSection . Ciò 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. Ciò incrementerà LockCount e EntryCount. RecursionCount non viene incrementato.

    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. Ciò decrementerà LockCount (a -1) e RecursionCount (a 0) e reimposterà OwningThread a 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. Ciò produce gli stessi risultati del thread proprietario che chiama LeaveCriticalSection: decrementerà LockCount (fino a -1) e RecursionCount (fino a 0) e reimposterà OwningThread su 0.

Quando un thread chiama LeaveCriticalSection, Windows decrementa LockCount e RecursionCount. Questa funzionalità presenta aspetti validi e negativi. Consente a un driver di dispositivo di immettere una sezione critica in un thread e lasciare la sezione critica in un altro thread. Tuttavia, consente anche di chiamare accidentalmente LeaveCriticalSection nel thread errato o di chiamare LeaveCriticalSection troppe volte e fare in modo che LockCount raggiunga valori inferiori a -1. Ciò danneggia la sezione critica e fa sì che tutti i thread attendano indefinitamente 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 indica se un thread è stato interrotto per questo blocco. Se questo bit è 0, un thread è stato svegliato per questo lucchetto; se è 1, nessun thread è stato svegliato.

  • 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 successivo può essere determinato in questo modo:

0:009> ? (0x2 & (-0n22)) >> 1
Evaluate expression: 1 = 00000001

Il complemento a uno dei bit rimanenti può essere determinato 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 risvegliato alcun thread per il 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 Microsoft Windows SDK, Windows Driver Kit (WDK) o Microsoft Windows Internals di Mark Russinovich e David Solomon.