互斥体真的慢了吗?

时间:2009-11-03 11:01:37

标签: windows multithreading mutex

我已经阅读了很多次,无论是在网络上还是网络上,互斥体都比关键部分/信号量/插入你的首选同步方法慢一些。但我从来没有见过任何论文或研究或其他什么来支持这一主张。

那么,这个想法来自哪里?这是神话还是现实?互斥体真的慢了吗?

5 个答案:

答案 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