C# 中的 Mutex 忙等待吗?

Does Mutex in C# busy wait?

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

根据文档,Mutex.WaitOne "Blocks the current thread until the current WaitHandle receives a signal",这意味着它已进入睡眠状态。


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

Waits until the specified object is in the signaled state, an I/O completion routine or asynchronous procedure call (APC) is queued to the thread, or the time-out interval elapses.

此外,根据 Context Switches

上的另一份文件

When a running thread needs to wait, it relinquishes the remainder of its time slice.

此处提供了一个很好的答案:When should one use a spinlock instead of a mutex?

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

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

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

None 这在单核机器上是有意义的,因为你只是在燃烧 CPU 而锁的持有者正在等待 运行 完成工作它需要做才能释放锁。单核机器上没有使用自适应锁

因此,直接回答您的问题 - Mutex class 可能会同时执行这两种操作 - 它会忙等待 (spin-wait) 一小会儿,看看它是否可以获取互斥锁在不执行上下文切换的情况下,如果它不能在允许的短时间内完成,它将挂起线程。重要的是要注意它的旋转等待时间通常很短,总的来说,这个策略可以显着减少总 CPU 使用或增加整体锁吞吐量。因此,即使我们正在燃烧 CPU 旋转等待,我们也可能会节省更多 CPU 总体。

在 .Net 上下文中,Mutex class 提供互斥,但要在多个进程之间使用,因此往往很慢。具体来说,Microsoft .Net Framework 中Mutex class 的实现,.Net Mutex class 使用了Win32 Mutex object

请注意,详细信息可能会根据您使用的 .Net 实现以及在哪个操作系统上发生变化。我已尝试对主题提供 .Net/Microsoft/Windows-centric 处理,因为这是最常见的情况。

顺便说一句,如果您只需要在单个进程中锁定,Monitor class, or its keyword lock, should be used instead. A similar dichotomy exists for semaphores - the Semaphore class is, in the end, implemented by the operating system - it can be used for inter-process communication and thus tends to be slow; the SemaphoreSlim class is implemented natively in .Net, can be used only within a single process, and tends to be faster. On this point, a good msdn article to read is Overview of Synchronization Primitives.