Sdílet prostřednictvím


Zobrazení kritického oddílu

Kritické části se dají zobrazit v uživatelském režimu různými metodami. Přesný význam jednotlivých polí závisí na verzi microsoft Windows, kterou používáte.

Zobrazení kritických oddílů

Kritické části lze zobrazit pomocí rozšíření !ntsdexts.locks, přípony !critsec, rozšíření !cs a příkazu dt (Typ zobrazení).

Rozšíření !ntsdexts.locks zobrazí seznam kritických sekcí přidružených k aktuálnímu procesu. Pokud se použije možnost -v , zobrazí se všechny důležité části. Tady je příklad:

0:000> !locks

CritSec ntdll!FastPebLock+0 at 77FC49E0
LockCount          0
RecursionCount     1
OwningThread       c78
EntryCount         0
ContentionCount    0
*** Locked

....
Scanned 37 critical sections

Pokud znáte adresu kritického oddílu, který chcete zobrazit, můžete použít rozšíření !critsec . Zobrazí se stejná kolekce informací jako !ntsdexts.locks. Například:

0:000> !critsec 77fc49e0

CritSec ntdll!FastPebLock+0 at 77FC49E0
LockCount          0
RecursionCount     1
OwningThread       c78
EntryCount         0
ContentionCount    0
*** Locked

Rozšíření !cs může zobrazit kritický oddíl na základě jeho adresy, vyhledat rozsah adres kritických oddílů a dokonce zobrazit trasování zásobníku přidružené ke každému kritickému oddílu. Některé z těchto funkcí vyžadují úplné symboly systému Windows, aby správně fungovaly. Pokud je aplikace Verifier aktivní, příkaz !cs -t může být použit k zobrazení stromu kritické sekce. Podrobnosti a příklady najdete na referenční stránce !cs .

Informace zobrazené souborem !cs se mírně liší od informací zobrazených pomocí !ntsdexts.locks a !critsec. Například:

## 0:000> !cs 77fc49e0

Critical section   = 0x77fc49e0 (ntdll!FastPebLock+0x0)
DebugInfo          = 0x77fc3e00
LOCKED
LockCount          = 0x0
OwningThread       = 0x00000c78
RecursionCount     = 0x1
LockSemaphore      = 0x0
SpinCount          = 0x00000000

Příkaz dt (Display Type) lze použít k doslovnému zobrazení obsahu struktury RTL_CRITICAL_SECTION. Například:

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

Interpretace polí kritického oddílu v systémech Windows XP a Windows 2000

Nejdůležitější pole struktury kritického oddílu jsou následující:

  • V systému Microsoft Windows 2000 a Windows XP pole LockCount označuje počet, kolikrát jakékoli vlákno volal EnterCriticalSection rutinu pro tuto kritickou část, minus jeden. Pro odemknutou kritickou část toto pole začíná na -1. Každé volání EnterCriticalSection zvýší tuto hodnotu; každý volání LeaveCriticalSection ho sníží. Pokud je například LockCount 5, je tento kritický oddíl uzamčený, jedno vlákno ho získalo a pět dalších vláken čeká na tento zámek.

  • Pole RecursionCount označuje počet, kolikrát vlastnící vlákno nazývá EnterCriticalSection pro tuto kritickou část.

  • Pole EntryCount označuje, kolikrát vlákno jiné než vlastnící vlákno nazývá EnterCriticalSection pro tuto kritickou část.

Nově inicializovaný kritický oddíl vypadá takto:

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

Ladicí program zobrazí hodnotu "NOT LOCKED" pro LockCount. Skutečná hodnota tohoto pole pro odemknutou kritickou část je -1. Můžete to ověřit pomocí příkazu dt (Typ zobrazení):

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

Když první vlákno volá rutinu EnterCriticalSection, pole LockCount, RecursionCount, EntryCount a ContentionCount kritické sekce se všechna zvýší o jedna a OwningThread bude ID volajícího vlákna. EntryCount a ContentionCount se nikdy nezmenšují. Například:

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

V tuto chvíli se můžou stát čtyři různé věci.

  1. Vlastnící vlákno znovu volá EnterCriticalSection. Tím se zvýší LockCount a RecursionCount. EntryCount se nevýšil.

    0:000> !critsec 433e60
    CritSec mymodule!cs+0 at 00433E60
    LockCount          1
    RecursionCount     2
    OwningThread       4d0
    EntryCount         0
    ContentionCount    0
    
  2. Jiné vlákno volá EnterCriticalSection. Tím se zvýší LockCount a EntryCount. RecursionCount se nevýšil.

    0:000> !critsec 433e60
    CritSec mymodule!cs+0 at 00433E60
    LockCount          1
    RecursionCount     1
    OwningThread       4d0
    EntryCount         1
    ContentionCount    1
    
  3. Vlastnící vlákno volá LeaveCriticalSection. Tím se dekrementuje LockCount (na -1) a RecursionCount (na 0) a resetuje OwningThread na 0.

    0:000> !critsec 433e60
    CritSec mymodule!cs+0 at 00433E60
    LockCount          NOT LOCKED 
    RecursionCount     0
    OwningThread       0
    EntryCount         0
    ContentionCount    0
    
  4. Další vlákno volá LeaveCriticalSection. Tím se dosáhne stejných výsledků jako při volání LeaveCriticalSection vlastnícím vláknem – dekrementuje LockCount (na -1) a RecursionCount (na 0) a resetuje OwningThread na 0.

Když některé programové vlákno volá LeaveCriticalSection, Windows snižuje LockCount a RecursionCount. Tato funkce má dobré i špatné aspekty. Umožňuje ovladači zařízení zadat kritický oddíl na jednom vlákně a ponechat kritický oddíl na jiném vlákně. Umožňuje však také omylem volat LeaveCriticalSection na nesprávném vlákně nebo volat LeaveCriticalSection příliš mnohokrát a způsobit LockCount dosažení hodnot nižších než -1. Tím dojde k poškození kritické sekce a způsobí, že všechna vlákna čekají na kritickou sekci neomezeně dlouho.

Interpretace polí kritického oddílu ve Windows Serveru 2003 SP1 a novějším

V systému Microsoft Windows Server 2003 Service Pack 1 a novějších verzích systému Windows se pole LockCount parsuje takto:

  • Nejnižší bit zobrazuje stav zámku. Pokud je tento bit 0, kritický oddíl je uzamčen; pokud je 1, kritická část není uzamčená.

  • Další bit ukazuje, zda bylo vlákno pro tento zámek probuzeno. Pokud je tento bit 0, bylo pro tento zámek probuzeno vlákno; pokud je 1, žádné vlákno nebylo probuzeno.

  • Zbývající bity jsou doplňkem počtu vláken čekajících na zámek.

Předpokládejme například, že LockCount je -22. Nejnižší bit lze takto určit:

0:009> ? 0x1 & (-0n22)
Evaluate expression: 0 = 00000000

Následující nejnižší bit lze určit tímto způsobem:

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

Jedničkový doplněk zbývajících bitů je možné určit tímto způsobem:

0:009> ? ((-1) - (-0n22)) >> 2
Evaluate expression: 5 = 00000005

V tomto příkladu je první bit 0, a proto je kritický oddíl uzamčený. Druhý bit je 1, a proto nebylo pro tento zámek probuzeno žádné vlákno. Doplněk zbývajících bitů je 5, takže existuje pět vláken čekajících na tento zámek.

Další informace

Informace o tom, jak ladit vypršení časových limitů kritických oddílů, najdete v tématu Vypršení časových limitů kritických oddílů. Obecné informace o důležitých částech naleznete v sadě Microsoft Windows SDK, Windows Driver Kit (WDK) nebo Microsoft Windows Internals od Marka Russinovicha a Davida Solomona.