我想知道Mutex
对象忙等待或上下文切换出来(即拥有互斥锁的线程是否进入休眠状态并稍后被中断唤醒),或者它是否依赖于体系结构(即你的机器有多少核心)?我希望它实际上是一个上下文切换出来的。提前谢谢。
答案 0 :(得分:8)
根据文档,Mutex.WaitOne
“阻止当前线程,直到当前WaitHandle收到信号”,这意味着它已进入休眠状态。
在内部,WaitHandle.WaitOne
会从Windows API调用WaitForSingleObjectEx
,其中:
等待指定的对象处于信号状态,I / O完成例程或异步过程调用(APC)排队到线程,或者超时间隔过去。
另外,根据Context Switches
上的另一份文件当正在运行的线程需要等待时,它会放弃其剩余的时间片。
答案 1 :(得分:6)
这里有一个很好的答案:When should one use a spinlock instead of a mutex?
答案是,这取决于。 .Net中的Mutex
类通常由操作系统支持,因为它是一个可以在多个进程之间共享的锁;它不能仅在一个过程中使用。
这意味着我们受操作系统实施的影响。大多数现代操作系统(包括Windows)都为多核计算机实现了自适应互斥锁。
从上面的答案中得出,我们了解到通过挂起线程来实现锁定通常非常昂贵,因为它需要至少2个上下文切换。在多核系统上,我们可以通过尝试最初旋转等待来获取锁来避免一些上下文切换 - 如果锁轻微争用,你可能会获得spinwait中的锁,因此永远不会遭受上下文切换/线程暂停。如果在spinwait发生时超时到期,则锁将降级为完全线程挂起,以避免浪费太多cpu。
这对于单核计算机来说没有任何意义,因为你只是在锁定持有者等待运行以完成它需要做的工作以释放锁定时烧掉CPU。单核机器上不使用自适应锁。
所以,要直接回答你的问题 - 很可能Mutex类同时执行这两个操作 - 它会忙 - 等待(旋转等待)一会儿,看它是否可以在不执行上下文切换的情况下获取互斥锁,如果它不能在很短的时间内完成,那么它就会暂停线程。重要的是要注意它旋转的时间通常非常短,总的来说,这种策略可以显着降低总CPU使用率或提高整体锁定吞吐量。因此,即使我们正在燃烧CPU等待旋转,我们也可能会节省更多的CPU。
在.Net的上下文中,Mutex
类提供了互斥,但是意味着在多个进程之间使用,因此往往非常慢。具体而言,Microsoft .Net Framework中Mutex
类的实现,.Net Mutex
类使用Win32 Mutex object。
请注意,详细信息可能会根据您正在使用的.Net的实现以及操作系统而改变。我试图提供以.Net / Microsoft / Windows为中心的主题,因为这是最常见的情况。
另外,如果您只需要在单个流程中进行锁定,则应使用Monitor class或其关键字lock
。信号量存在类似的二分法 - Semaphore
类最终由操作系统实现 - 它可以用于进程间通信,因此往往很慢; SemaphoreSlim
类本身在.Net中实现,只能在单个进程中使用,并且往往更快。在这一点上,一篇好的msdn文章是Overview of Synchronization Primitives。