Windows でのクリティカル セクションの実装は長年にわたって変更されてきましたが、常にユーザー モードとカーネル呼び出しの組み合わせでした。
CRITICAL_SECTION は、ユーザー モードで更新された値、カーネル モード オブジェクト (EVENT など) へのハンドル、およびデバッグ情報を含む構造体です。
EnterCriticalSection は、ロックを取得するために連動テスト アンド セット操作を使用します。成功した場合、必要なのはこれだけです (ほとんどの場合、所有者スレッドも更新されます)。test-and-set 操作が取得に失敗した場合は、より長いパスが使用されます。これには、通常、カーネル オブジェクトを で待機する必要がありますWaitForSignleObject
。InitializeCriticalSectionAndSpinCount
thenで初期化した場合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
つまり、スレッドがブロックする必要がない場合、スレッドはシステム コールを使用せず、インターロックされたテストと設定の操作だけを使用します。ブロックが必要な場合は、システム コールが発生します。リリース パスも連動したテスト アンド セットを使用し、他のスレッドがブロックされている場合はシステム コールが必要になる場合があります。
これを、常にシステム コールNtWaitForSingleObject
を必要とする Mutex と比較してください。NtReleaseMutant