windows 互斥锁真的很慢吗?

csga3l58  于 2023-02-25  发布在  Windows
关注(0)|答案(5)|浏览(209)

我已经读了很多遍,在这里和网上的任何地方,互斥锁比临界区/信号量/插入你的首选同步方法慢,但是我从来没有看到任何论文或研究或任何东西来支持这个说法。
那么,这个想法从何而来?是神话还是现实?互斥锁真的很慢吗?

8yparm6h

8yparm6h1#

在Jim Beveridge和Robert Wiener所著的《Win32中的多线程应用程序》一书中,它说:“锁定无主互斥锁所需的时间几乎是锁定无主临界区所需时间的100倍,因为临界区可以在用户模式下完成,而不涉及内核”
在MSDN here上,它说“临界区对象为互斥同步提供了一种稍微更快、更有效的机制”

zzoitvuj

zzoitvuj2#

我不相信任何一个答案都触及到了他们为什么不同的关键点。
互斥锁位于操作系统级别。存在一个命名互斥锁,并且可以从操作系统中的任何进程访问它(前提是它的ACL允许从所有进程访问)。
临界区的速度更快,因为它们不需要系统调用进入内核模式,但是它们只在WITHIN一个进程内工作,你不能使用临界区锁定多个进程。所以根据你想要达到的目标和你的软件设计,你应该选择最合适的工具来完成这项工作。
我还要向你指出,信号量与互斥体/临界区是分开的,因为它们的计数不同。信号量可以用来控制对资源的多个并发访问,其中互斥体/临界区要么被访问,要么不被访问。

tjjdgumg

tjjdgumg3#

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:获取/释放缓慢,但长“锁定区域”不会浪费周期
临界截面:快速获取/发布无主“区域”,但浪费了有主部分的周期。

oxcyiej7

oxcyiej74#

是的,临界区更有效率。要想得到一个非常好的解释,请参阅"Windows上的并发编程"。
简而言之:互斥体是一个内核对象,所以当你获取一个互斥体时,即使它是"空闲的",也总是会有一个上下文切换。2在这种情况下,一个临界区可以在没有上下文切换的情况下被获取,并且(在多核/处理器机器上)如果它被阻塞以防止昂贵的上下文切换,它甚至会旋转几个周期。

chhkpiq4

chhkpiq45#

互斥锁(至少在windows中)允许线程之外的不同进程之间的同步。这意味着必须做额外的工作来确保这一点。而且,正如Brian所指出的,使用互斥锁还需要切换到“内核”模式,这会导致另一次速度打击(我 * 相信 *,即推断,内核是这个进程间同步所必需的,但我没有任何证据支持我)。
编辑:您可以找到对进程间同步here的显式引用,有关此主题的更多信息,请参阅Interprocess Synchronization

相关问题