2011-03-03 39 views
3

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

我刚刚在this book中读到这些句子。
内核系统调用的含义是什么?你能给我这个函数的名字吗?

我是英国的新手。我这样解释他们。

  • CS测试不使用系统调用。
  • 互斥测试使用系统调用(但我不知道函数名称,请告诉我)
  • CS解锁不会调用系统调用。
  • 互斥解锁需要一个系统调用。(但我不知道该功能的名称。让我知道)

另一个问题。

  • 我觉得CRITICAL_SECTION可能会调用WaitForSingleObject或家族函数。这些功能不需要系统调用吗?我猜他们会。所以CS测试不使用系统调用对我来说很怪异。
+0

互斥使用'CreateMutex'。 – Mehrdad 2011-03-03 03:01:06

+0

自旋锁实际上是用于内核使用的(当然,您可以在自己的程序中不做任何事情,但这没有帮助)。以下关于自旋锁的答案以前是误导性的,但现在海报已经纠正了它。 – casablanca 2011-03-03 03:28:51

+0

抱歉有关混淆。 – 0xC0000022L 2011-03-03 03:35:19

回答

4

多年来,Windows中关键部分的实现已经发生了变化,但它一直是用户模式和内核调用的结合。

CRITICAL_SECTION是一个包含用户模式更新值,内核模式对象的句柄-EVENT或类似的东西以及调试信息的结构。

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 

因此,底线是,如果线程并不需要一个diassembly阻止它不会使用系统调用,只是互锁的测试和设置操作。如果需要阻止,则会有系统调用。释放路径也使用互锁测试和设置,并且如果其他线程被阻塞,可能需要系统调用。

比较这对互斥总是需要一个系统调用NtWaitForSingleObjectNtReleaseMutant

3

调用内核需要上下文切换,这是需要每一个上下文切换一个小的(但可衡量)的性能损失。有问题的功能是ReleaseMutex()本身。

kernel32.dll(至少从调用者的角度来看 - 关于ntdll.dll的讨论请参见注释)中提供了关键部分功能,并且通常可以避免向内核发出任何调用。

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

+0

其他正在讨论的函数是等待函数之一,例如用于获取互斥锁的'WaitForSingleObject',它又一次引发系统调用。 – casablanca 2011-03-03 03:00:52

+0

@Greg Hewgill:对不起,我必须纠正你的错误,但它是一个简单的函数转发器(在导出表内)指向'NTDLL.RtlEnterCriticalSection'。 – 0xC0000022L 2011-03-03 03:01:23

+0

系统调用与上下文切换不同。转换到内核会增加特权级别,但不必保存浮点状态,重新配置页表或与上下文切换相关的其他复杂性。 – 2011-03-03 03:03:06

1

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

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

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

+0

自旋锁在内核之间相互排斥,因为它们浪费周期而非常谨慎地使用。用户线程无法承受旋转无所事事 - 锁定测试在用户空间中完成,但如果锁定不空闲,线程仍会阻塞。 – casablanca 2011-03-03 03:19:24

+0

@casablanca:对不起,由于使用了InitializeCriticalSectionAndSpinCount,我很困惑。它使用信号量。 – 0xC0000022L 2011-03-03 03:22:39

+0

我已删除我的downvote。此外,有关'lock'前缀的部分是正确的 - 它确实用于测试锁,但它与自旋锁不同。 – casablanca 2011-03-03 03:26:39

1

如果存在争用,临界区域调用仅转换到内核模式,并且只有在它们不能通过旋转来缓解争用时才会进入内核模式。在这种情况下,线程会阻塞并调用一个等待函数 - 这是一个系统调用。