Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Критические разделы можно отображать в пользовательском режиме различными методами. Точное значение каждого поля зависит от используемой версии Microsoft Windows.
Отображение критических разделов
Критические разделы можно отобразить с помощью расширения !ntsdexts.locks, расширения !critsec, расширения !cs и команды dt (тип отображения).
Расширение !ntsdexts.locks отображает список критически важных разделов, связанных с текущим процессом. Если используется параметр -v , отображаются все критические разделы. Ниже приведен пример:
0:000> !locks
CritSec ntdll!FastPebLock+0 at 77FC49E0
LockCount 0
RecursionCount 1
OwningThread c78
EntryCount 0
ContentionCount 0
*** Locked
....
Scanned 37 critical sections
Если вы знаете адрес критического раздела, который вы хотите отобразить, можно использовать расширение !critsec . В результате отображается такую же коллекцию сведений, как и !ntsdexts.locks. Рассмотрим пример.
0:000> !critsec 77fc49e0
CritSec ntdll!FastPebLock+0 at 77FC49E0
LockCount 0
RecursionCount 1
OwningThread c78
EntryCount 0
ContentionCount 0
*** Locked
Расширение !cs может отображать критически важный раздел на основе своего адреса, искать диапазон адресов для критических разделов и даже отображать трассировку стека, связанную с каждым критическим разделом. Некоторые из этих функций требуют правильной работы полных символов Windows. Если средство проверки приложений активно, !cs -t можно использовать для отображения дерева критически важных разделов. Дополнительные сведения и примеры см. на странице справки !cs .
Сведения, отображаемые !cs, слегка отличаются от тех, что показаны в !ntsdexts.locks и !critsec. Рассмотрим пример.
## 0:000> !cs 77fc49e0
Critical section = 0x77fc49e0 (ntdll!FastPebLock+0x0)
DebugInfo = 0x77fc3e00
LOCKED
LockCount = 0x0
OwningThread = 0x00000c78
RecursionCount = 0x1
LockSemaphore = 0x0
SpinCount = 0x00000000
Команда dt (тип отображения) может использоваться для отображения литерального содержимого структуры RTL_CRITICAL_SECTION. Рассмотрим пример.
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
Интерпретация критически важных полей раздела в Windows XP и Windows 2000
Наиболее важными полями структуры критически важных разделов являются следующие:
В Microsoft Windows 2000 и Windows XP поле LockCount указывает количество раз, когда любой поток вызвал подпрограмму EnterCriticalSection для этого критического раздела, минус один. Это поле начинается с -1 для разблокированного критического раздела. Каждый вызов EnterCriticalSection увеличивает это значение; каждый вызов LeaveCriticalSection уменьшает его. Например, если lockCount равен 5, этот критически важный раздел заблокирован, один поток приобрел его, и пять дополнительных потоков ожидают этой блокировки.
Поле RecursionCount указывает количество раз, когда собственный поток назвал ВводCriticalSection для этого критического раздела.
Поле EntryCount указывает количество раз, которое поток, отличный от владельца потока, вызвал EnterCriticalSection для этого критического раздела.
Новый инициализированный критический раздел выглядит следующим образом:
0:000> !critsec 433e60
CritSec mymodule!cs+0 at 00433E60
LockCount NOT LOCKED
RecursionCount 0
OwningThread 0
EntryCount 0
ContentionCount 0
Отладчик отображает значение NOT LOCKED в качестве значения lockCount. Фактическое значение этого поля для разблокированного критического раздела равно -1. Это можно проверить с помощью команды dt (тип отображения ):
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
Когда первый поток вызывает подпрограмму EnterCriticalSection, поля критической секции LockCount, RecursionCount, EntryCount и ContentionCount все увеличиваются на единицу, и OwningThread становится идентификатором потока вызывающего. EntryCount и ContentionCount никогда не уменьшаются. Рассмотрим пример.
0:000> !critsec 433e60
CritSec mymodule!cs+0 at 00433E60
LockCount 0
RecursionCount 1
OwningThread 4d0
EntryCount 0
ContentionCount 0
На этом этапе может произойти четыре разных события.
Собственный поток снова вызывает EnterCriticalSection . Это увеличит LockCount и RecursionCount. EntryCount не увеличивается.
0:000> !critsec 433e60 CritSec mymodule!cs+0 at 00433E60 LockCount 1 RecursionCount 2 OwningThread 4d0 EntryCount 0 ContentionCount 0Другой поток вызывает EnterCriticalSection. Это увеличит LockCount и EntryCount. RecursionCount не увеличивается.
0:000> !critsec 433e60 CritSec mymodule!cs+0 at 00433E60 LockCount 1 RecursionCount 1 OwningThread 4d0 EntryCount 1 ContentionCount 1Собственный поток вызывает LeaveCriticalSection. Это приведет к уменьшению блокировки (до -1) и RecursionCount (до 0) и сбросит значение 0.
0:000> !critsec 433e60 CritSec mymodule!cs+0 at 00433E60 LockCount NOT LOCKED RecursionCount 0 OwningThread 0 EntryCount 0 ContentionCount 0Другой поток вызывает LeaveCriticalSection. Это даёт тот же результат, что и вызов LeaveCriticalSection: он уменьшит LockCount (до -1), RecursionCount (до 0), и сбросит OwningThread на 0.
Когда любой поток вызывает LeaveCriticalSection, Windows уменьшает LockCount и RecursionCount. Эта функция имеет как хорошие, так и плохие аспекты. Он позволяет драйверу устройства ввести критически важный раздел в одном потоке и оставить критически важный раздел в другом потоке. Однако он также позволяет случайно вызвать LeaveCriticalSection в неправильном потоке или вызвать LeaveCriticalSection слишком много раз и вызвать LockCount достичь значений ниже -1. Это повреждает критически важный раздел и приводит к тому, что все потоки будут ждать неограниченное время в критическом разделе.
Интерпретация полей критической секции в Windows Server 2003 SP1 и позже
В Microsoft Windows Server 2003 с пакетом обновления 1 и более поздних версий Windows поле LockCount анализируется следующим образом:
Самый низкий бит показывает состояние блокировки. Если этот бит равен 0, критически важный раздел заблокирован; Если значение равно 1, критически важный раздел не заблокирован.
Следующий бит показывает, проснулся ли поток для этой блокировки. Если этот бит равен 0, поток был пробужден для этой блокировки; если этот бит равен 1, поток не был пробужден.
Остальные биты являются дополнением числа потоков, ожидающих блокировки.
Например, предположим, что LockCount — -22. Самый низкий бит можно определить таким образом:
0:009> ? 0x1 & (-0n22)
Evaluate expression: 0 = 00000000
Следующий самый низкий бит можно определить таким образом:
0:009> ? (0x2 & (-0n22)) >> 1
Evaluate expression: 1 = 00000001
Таким образом можно определить единичное дополнение оставшихся битов:
0:009> ? ((-1) - (-0n22)) >> 2
Evaluate expression: 5 = 00000005
В этом примере первый бит равен 0, поэтому критически важный раздел заблокирован. Второй бит равен 1, и поэтому поток не проснулся для этой блокировки. Дополнение оставшихся битов составляет 5, и поэтому есть пять потоков, ожидающих этой блокировки.
дополнительные сведения
Для получения сведений о том, как отлаживать время ожидания в критических разделах, см. Времени ожидания в критических разделах. Общие сведения о критически важных разделах см. в пакете SDK для Microsoft Windows, комплекте драйверов Windows (WDK) или внутренних компонентах Microsoft Windows марком Руссиновичем и Дэвидом Соломоном.