互斥真的很慢吗?

我已经阅读了很多次,在这里和在网上的任何地方,互斥体比关键节/信号量/ insert-your-preferred-synchronization-method-here要慢。 但我从来没有看到任何文件或研究或任何备份这一说法。

那么,这个想法从哪里来? 这是一个神话还是一个现实? 互斥真的很慢?

Solutions Collecting From Web of "互斥真的很慢吗?"

在Jim Beveridge和Robert Wiener的“多线程应用程序在win32中”一书中,他说:“锁定一个无主的互斥锁要比锁定一个无主的关键部分要快100倍,因为关键部分可以在用户模式下完成,而无需涉及内核“

在msdn上它说:“临界区对象为互斥同步提供了一个更快,更高效的机制”

我不相信任何答案都会影响他们为什么不同的关键点。

互斥体在操作系统级别。 存在一个已命名的互斥体,可以从操作系统中的任何进程访问(只要其ACL允许全部访问)。

关键部分速度更快,因为它们不需要将系统调用到内核模式,但是它们只能在进程内工作,不能使用关键部分锁定多个进程。 所以,根据你所要达到的目标以及你的软件设计,你应该选择最合适的工具。

另外我还要指出,由于数量的限制,信号量与互斥/关键部分是分开的。 信号量可用于控制对资源的多个并发访问,其中作为互斥/关键部分被访问或不被访问。

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->coreelLock, INFINITE ); } 

所以如果你的关键部分只保持很短的时间,而且进入的线程只等待很少的“旋转”(周期),那么关键部分可以是非常有效的。 但是如果不是这样的话,临界区会浪费许多无用的循环,然后又回退到内核同步对象。

所以权衡是:

互斥锁 :缓慢的获取/释放,但没有浪费周期长'锁定地区'

CRITICAL_SECTION :快速获取/释放为无主的“地区”,但浪费自有部分的周期。

是的,关键部分更有效率。 对于一个很好的解释,得到“Windows上的并行编程”。

简而言之:互斥量是一个内核对象,所以当你获取一个互斥量的时候,总会有一个上下文切换,即使是“自由”也是如此。 在这种情况下,可以在没有上下文切换的情况下获取关键部分,并且(在多核/处理器机器上)甚至可以旋转几个周期(如果被阻塞),以防止昂贵的上下文切换。

一个互斥体(至少在windows中)允许除了线程之外的不同进程之间的同步。 这意味着必须做额外的工作来确保这一点。 另外,正如Brian所指出的那样 ,使用互斥锁还需要切换到“内核”模式,这会导致另一个速度命中(我相信 ,即推断内核是进程间同步所必需的,但我没有任何东西可以支持我在这上面)。

编辑:您可以在这里找到进程间同步的明确引用,有关此主题的更多信息,请参阅进程间同步