我已经阅读了很多次,无论是在网络上还是网络上,互斥体都比关键部分/信号量/插入你的首选同步方法慢一些。但我从来没有见过任何论文或研究或其他什么来支持这一主张。
那么,这个想法来自哪里?这是神话还是现实?互斥体真的慢了吗?
答案 0 :(得分:18)
在Jim Beveridge和Robert Wiener的“win32中的多线程应用程序”一书中,它说:“锁定无主的互斥锁需要比锁定无关的关键部分多近100倍,因为关键部分可以在用户模式,不涉及内核“
在msdn here上,它说“关键部分对象提供了一种更快,更有效的互斥同步机制”
答案 1 :(得分:15)
我不相信任何答案都会触及他们与众不同的关键点。
互斥锁处于操作系统级别。存在一个已命名的互斥锁,可以从操作系统中的任何进程访问(前提是其ACL允许所有进程访问)。
关键部分更快,因为它们不需要将系统调用进入内核模式,但是它们只能在 WITHIN 进程中运行,您无法使用关键部分锁定多个进程。因此,根据您要实现的目标和软件设计的外观,您应该选择最合适的工具。
我还要向你指出,信号量与互斥/关键部分是分开的,因为它们的数量。信号量可用于控制对资源的多个并发访问,其中正在访问或未访问互斥/临界区。
答案 2 :(得分:5)
CRITICAL_SECTION实现为具有上限旋转计数的自旋锁。请参阅MSDN InitializeCriticalSectionAndSpinCount了解相关信息。
当旋转计数'过去'时,临界区锁定一个信号量(或者它实现的任何内核锁)。
所以在代码中它的工作原理是这样的(不是真的有效,应该只是一个例子):
CRITICAL_SECTION s;
void EnterCriticalSection( CRITICAL_SECTION* s )
{
int spin_count = s.max_count;
while( --spin_count >= 0 )
{
if( InterlockedExchange( &s->Locked, 1 ) == 1 )
{
// we own the lock now
s->OwningThread = GetCurrentThread();
return;
}
}
// lock the mutex and wait for an unlock
WaitForSingleObject( &s->KernelLock, INFINITE );
}
因此,如果您的关键部分只保持很短的时间,并且进入的线程仅等待很少的“旋转”(循环),则关键部分可以非常有效。但如果不是这种情况,那么关键部分会浪费许多循环,什么都不做,然后又回退到内核同步对象。
所以权衡是:
Mutex : 缓慢获取/释放,但长期“锁定区域”没有浪费周期
CRITICAL_SECTION :快速获取/释放未拥有的“区域”,但浪费了自有部分的周期。
答案 3 :(得分:3)
是的,关键部分更有效率。要获得非常好的解释,请获取“Windows上的并发编程”。
简而言之:互斥锁是一个内核对象,所以当你获得一个互斥锁时,总会有一个上下文切换,即使是“免费”。在这种情况下,可以在没有上下文切换的情况下获取关键部分,并且(在多核/处理器机器上)如果被阻止则甚至会旋转几个周期以防止昂贵的上下文切换。
答案 4 :(得分:2)
除了线程之外,互斥锁(至少在Windows中)允许不同进程之间的同步。这意味着必须做额外的工作来确保这一点。此外,作为Brian pointed out,使用互斥锁还需要切换到“内核”模式,这会导致另一个速度命中(我相信,即推断,内核是此进程间同步所必需的,但我没有什么可以支持我的。)
编辑:您可以找到对进程间同步here的显式引用,有关此主题的更多信息,请查看Interprocess Synchronization