4

CRITICAL_SECTION 锁定(进入)和解锁(离开)是有效的,因为 CS 测试是在用户空间中执行的,而不需要像互斥体那样进行内核系统调用。解锁完全在用户空间中执行,而 ReleaseMutex 需要系统调用。

我刚刚在这本书中读到了这些句子。
内核系统调用是什么意思?你能给我函数的名字吗?

我是一个英语新手。我是这样解释他们的。

  • CS 测试不使用系统调用。
  • 互斥测试使用系统调用。(但我不知道函数名称。请告诉我)
  • CS解锁不调用系统调用。
  • 互斥解锁需要系统调用。(但我不知道函数名称。请告诉我)

另一个问题。

  • 我认为 CRITICAL_SECTION 可能会调用 WaitForSingleObject 或家庭函数。这些功能不需要系统调用吗?我想他们会的。所以CS 测试不使用系统调用对我来说很奇怪。
4

4 回答 4

5

多年来,Windows 中临界区的实现发生了变化,但它始终是用户模式和内核调用的组合。

The CRITICAL_SECTION is a structure that contains a user-mode updated values, a handle to a kernel-mode object - EVENT or something like that, and debug information.

EnterCriticalSection uses an interlocked test-and-set operation to acquire the lock. If successful, this is all that is required (almost, it also updates the owner thread). If the test-and-set operation fails to aquire, a longer path is used which usually requires waiting on a kernel object with WaitForSignleObject. If you initialized with InitializeCriticalSectionAndSpinCount then EnterCriticalSection may spin an retry to acquire using interlocked operation in user-mode.

Below is a diassembly of the "fast" / uncontended path of EnterCriticialSection in Windows 7 (64-bit) with some comments inline

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

于 2011-05-21T05:01:27.833 回答
4

调用内核需要上下文切换,每次上下文切换都会对性能造成很小(但可测量)的影响。有问题的功能就是ReleaseMutex()它本身。

临界区函数是可用的kernel32.dll(至少从调用者的角度来看 - 请参阅有关讨论的评论ntdll.dll),并且通常可以避免对内核进行任何调用。

值得知道的是,Mutex 对象可以同时从不同的进程访问。另一方面,CRITICAL_SECTION对象仅限于一个进程。

于 2011-03-03T02:55:05.093 回答
1

据我所知,关键部分是使用信号量实现的。

临界区函数在 NTDLL 中实现,它在用户模式下实现一些运行时函数并将控制权传递给其他内核(系统调用)。kernel32.dll 中的函数是简单的函数转发器。

另一方面,互斥锁是内核对象,因此需要系统调用。顺便说一句,内核称它们为“突变体”(不是开玩笑)。

于 2011-03-03T03:06:50.690 回答
1

临界区调用仅在存在争用且无法通过旋转缓解争用时才转换到内核模式。在这种情况下,线程阻塞并调用一个等待函数——这是一个系统调用。

于 2011-03-03T07:19:58.173 回答