C#中的互斥锁是不是忙等待?

Posted

技术标签:

【中文标题】C#中的互斥锁是不是忙等待?【英文标题】:Does Mutex in C# busy wait?C#中的互斥锁是否忙等待? 【发布时间】:2015-05-26 13:52:24 【问题描述】:

我想知道 Mutex 对象是否忙于等待或上下文切换(即拥有互斥锁的线程是否进入睡眠状态并稍后被中断唤醒),或者它是否依赖于体系结构(即你的机器有核心)?我希望它实际上会切换上下文。提前谢谢你。

【问题讨论】:

【参考方案1】:

根据文档,Mutex.WaitOne“阻塞当前线程,直到当前 WaitHandle 收到信号”,这意味着它已进入睡眠状态。


在内部,WaitHandle.WaitOne 将从 Windows API 调用 WaitForSingleObjectEx,其中:

等到指定对象处于信号状态、I/O 完成例程或异步过程调用 (APC) 排队到线程中,或者超时间隔已过。

另外,根据Context Switches上的另一份文件

当正在运行的线程需要等待时,它会放弃剩余的时间片。

【讨论】:

好吧,SpinWait 也会阻塞当前线程——但没有上下文切换。我猜 WaitHandle 部分是 OP 所要求的。 @Agent_L Thread.SpinWait 的文档将其描述为“导致线程等待迭代参数定义的次数”。请注意,文档中没有提到“块”这个词。我认为可以安全地假设这里的“阻塞”意味着“使线程进入睡眠状态”。 @dcastro:-1。你没有回答提问者的问题。问题的核心是 mutex 是如何实现阻塞的,这里的“阻塞”是什么意思。假设阻塞 == 睡眠是不安全的,因为烧毁 CPU 和从运行队列中移除都是“阻塞”的有效方式。事实上,现代互斥体实现,*具有平台相关特性,倾向于将两者用作混合方法的一部分——如果没有竞争,则最初使用自旋等待将线程保持在 CPU 上,否则睡觉。 @antiduh 我在回答中添加了更多细节,希望它清楚地表明“阻塞”并不意味着忙于等待。 @dcastro - 那么你的回答是误导或不正确的。 Mutex.WaitOne(),由 Microsoft .Net 框架实现,确实使用忙等待 - 它由自适应互斥体实现。它会忙——等待一小会儿,试图抓住锁。如果它无法在其线程量子到期之前获取锁,它将停止忙等待并转而休眠。 互斥锁可以在不休眠的情况下阻塞.【参考方案2】:

这里有一个很好的答案:When should one use a spinlock instead of a mutex?

答案是视情况而定。 .Net 中的Mutex 类通常由操作系统支持,因为它是一个可以在多个进程之间共享的锁;它不打算仅在单个进程中使用。

这意味着我们受制于操作系统的实施。大多数现代操作系统(包括 Windows)都为多核机器实现了自适应互斥锁。

从上面的答案中,我们了解到通过挂起线程来实现锁定通常非常昂贵,因为它至少需要 2 次上下文切换。在多核系统上,我们可以通过尝试旋转等待最初获取锁来避免一些上下文切换 - 如果锁被轻微争用,您可能会在旋转等待中获取锁,因此永远不会遭受惩罚上下文切换/线程暂停。在 spinwait 发生时超时到期的情况下,锁将降级为全线程暂停,以防止浪费过多的 cpu。

这在单核机器上没有任何意义,因为您只会在锁的持有者等待运行以完成释放锁所需的工作时消耗 CPU。单核机器上不使用自适应锁。

所以,直接回答您的问题 - Mutex 类很可能两者兼而有之 - 它会忙等待(自旋等待)一会儿,看看它是否可以在不执行上下文切换的情况下获取互斥锁,如果它不能在它允许的短时间内这样做,它会挂起线程。需要注意的是,它自旋等待的时间通常很短,总体而言,这种策略可以显着降低 CPU 总使用率或提高整体锁吞吐量。因此,即使我们正在消耗 CPU 旋转等待,我们也可能会总体上节省更多 CPU。

在 .Net 的上下文中,Mutex 类提供互斥,但旨在用于多个进程之间,因此往往很慢。具体来说,微软.Net Framework中Mutex类的实现,.NetMutex类使用Win32 Mutex object。

请注意,具体细节可能会根据您使用的 .Net 实现以及操作系统而有所不同。我尝试提供以 .Net/Microsoft/Windows 为中心的主题处理方式,因为这是最常见的情况。

顺便说一句,如果您只需要在单个进程中锁定,则应使用Monitor class 或其关键字lock 来代替。信号量也存在类似的二分法——Semaphore 类最终由操作系统实现——它可用于进程间通信,因此速度较慢; SemaphoreSlim 类在 .Net 中本地实现,只能在单个进程中使用,而且速度更快。关于这一点,一篇好的msdn文章是Overview of Synchronization Primitives。

【讨论】:

以上是关于C#中的互斥锁是不是忙等待?的主要内容,如果未能解决你的问题,请参考以下文章

互斥锁,自旋锁,原子操作原理和实现

提升进程间互斥锁崩溃而不是等待锁定?

内核同步机制

互斥锁线程是不是使用 CPU 时间?

C# 互斥量处理

c#中的监视器与互斥锁[重复]