Реализация критических разделов в Windows менялась с годами, но всегда была комбинацией вызовов режима пользователя и ядра.
CRITICAL_SECTION - это структура, которая содержит обновленные значения пользовательского режима, дескриптор объекта режима ядра - СОБЫТИЕ или что-то подобное и отладочную информацию.
EnterCriticalSection использует блокированный тести установить операцию для получения блокировки.В случае успеха это все, что требуется (почти также обновляет поток владельца).Если операция set-and-set завершается неудачно, используется более длинный путь, который обычно требует ожидания объекта ядра с WaitForSignleObject
.Если вы инициализировали с InitializeCriticalSectionAndSpinCount
, то EnterCriticalSection
может выполнить повторную попытку для получения, используя блокированную операцию в пользовательском режиме.
Ниже приведена разборка «быстрого» / необоснованного пути EnterCriticialSection
в Windows 7 (64-разрядная версия) с некоторыми встроенными комментариями
0:000> u rtlentercriticalsection rtlentercriticalsection+35
ntdll!RtlEnterCriticalSection:
00000000`77ae2fc0 fff3 push rbx
00000000`77ae2fc2 4883ec20 sub rsp,20h
; RCX points to the critical section rcx+8 is the LockCount
00000000`77ae2fc6 f00fba710800 lock btr dword ptr [rcx+8],0
00000000`77ae2fcc 488bd9 mov rbx,rcx
00000000`77ae2fcf 0f83e9b1ffff jae ntdll!RtlEnterCriticalSection+0x31 (00000000`77ade1be)
; got the critical section - update the owner thread and recursion count
00000000`77ae2fd5 65488b042530000000 mov rax,qword ptr gs:[30h]
00000000`77ae2fde 488b4848 mov rcx,qword ptr [rax+48h]
00000000`77ae2fe2 c7430c01000000 mov dword ptr [rbx+0Ch],1
00000000`77ae2fe9 33c0 xor eax,eax
00000000`77ae2feb 48894b10 mov qword ptr [rbx+10h],rcx
00000000`77ae2fef 4883c420 add rsp,20h
00000000`77ae2ff3 5b pop rbx
00000000`77ae2ff4 c3 ret
Таким образом, суть в том, что еслипотоку не нужно его блокировать, он не будет использовать системный вызов, а только блокированную операцию проверки и установки.Если требуется блокировка, произойдет системный вызов.Путь освобождения также использует блокированный тест и набор и может потребовать системного вызова, если другие потоки заблокированы.
Сравните это с Mutex, который всегда требует системного вызова NtWaitForSingleObject
и NtReleaseMutant