2011-05-03 144 views
219

我认为两者都在做同样的工作,你如何决定使用哪一个进行同步?什么时候应该使用自旋锁而不是互斥锁?

+1

可能重复[Spin​​lock Versus Semaphore!](http://stackoverflow.com/questions/195853/spinlock-versus-semaphore) – 2011-05-03 13:21:28

+7

互斥和信号量不是一回事,所以我不认为这是一个重复。引用的文章的答案正确地说明了这一点。 欲了解更多详情,请参阅http://www.barrgroup.com/Embedded-Systems/How-To/RTOS-Mutex-Semaphore – nanoquack 2014-04-28 05:05:50

回答

568

理论

从理论上讲,当一个线程试图锁定一个互斥体,它并没有成功,因为互斥已被锁定,这将转入休眠状态,立即允许另一个线程来运行。它会继续睡觉直到被唤醒,一旦这个互斥锁被任何线程锁定之前解锁,情况就是这样。当一个线程试图锁定一个自旋锁并且它不成功时,它会不断地重新尝试锁定它,直到它最终成功;因此它不会允许另一个线程取代它的位置(但是,当然,一旦当前线程的CPU运行时间量已超出,操作系统将强制切换到另一个线程)。

的问题

与互斥的问题是,把线程睡眠和觉醒起来又都是相当昂贵的操作,他们将需要相当多的CPU指令,因此还需要一些时间。如果现在互斥锁只能锁定很短的时间,那么将线程休眠并再次唤醒的时间可能会超过线程实际睡眠的时间,甚至可能超过线程的时间因不断投票自旋而浪费了。另一方面,对自旋锁进行轮询会不断浪费CPU时间,如果锁持续更长的时间,这将浪费更多的CPU时间,而如果线程正在休眠,则会更好。

单核/单CPU系统上的使用自旋锁使得通常没有意义的,因为只要自旋锁轮询阻塞唯一可用的CPU核心,没有其他线程可以运行和由于没有其他线程可以运行,锁也不会被解锁。 IOW,一个自旋锁只浪费CPU时间在这些系统上没有真正的好处。如果线程进入睡眠状态,另一个线程可能立即运行,可能会解锁该锁,然后允许第一个线程继续处理,一旦它再次醒来。

在一个多核/多CPU系统上,只有很短的时间才会锁住大量的锁,浪费时间不断地让线程进入休眠状态并再次唤醒线程可能会显着降低运行时性能。当使用自旋锁代替时,线程有机会利用完整的运行时间量(总是只在很短的时间段内阻塞,但随后立即继续工作),从而导致更高的处理吞吐量。

实践

因为很多时候程序员不能提前知道,如果互斥体或自旋锁会更好(例如,因为目标架构的CPU核心数量不详),也不操作系统可以知道,如果一个某些代码已针对单核或多核环境进行了优化,大多数系统不会严格区分互斥和自旋锁。事实上,大多数现代操作系统都有混合互斥和混合自旋锁。这实际上意味着什么?

在多核系统上,混合互斥锁起初就像一个自旋锁一样。如果一个线程无法锁定互斥锁,它将不会立即进入睡眠状态,因为互斥锁可能很快就会被解锁,所以互斥量将首先表现得像一个自旋锁。只有在特定时间(或重试或任何其他测量因素)后还没有获得锁定时,线程才真正进入睡眠状态。如果相同的代码只在一个只有一个内核的系统上运行,那么互斥量将不会自旋锁,尽管如上所述,这并不会有好处。

的混合自旋锁的行为就像在第一次正常的自旋锁,但要避免浪费过多的CPU时间,它可能有一个回退的策略。它通常不会让线程进入睡眠状态(因为使用spinlock时不希望发生这种情况),但它可能会决定停止线程(立即或在一段时间后)并允许另一个线程运行,从而增加了自旋锁解锁的机会(一个纯线程切换通常比一个线程睡眠并稍后再次唤醒线程更便宜,尽管不是很远)。

摘要

如有疑问,使用互斥,他们通常是更好的选择,最现代化的系统将允许他们自旋锁的时间很短的量,如果这似乎是有益的。使用自旋锁有时可以提高性能,但只有在某些条件下,以及您有疑问的事实才会告诉我,您目前没有在任何可能有利于自旋锁的项目上工作。您可以考虑使用自己的“锁定对象”,即可以使用一个自旋锁或互斥体内部(例如创建这样一个对象时,此行为可能是可配置的),最初使用互斥无处不在,如果你认为某个地方使用自旋锁可能真的帮助,给它一个尝试,并比较结果(例如使用分析器),但要确保你妄下结论(也可能是不同的操作系统之前,如果你的代码来测试这两种情况下,单核和多核系统将是跨平台的)。

+2

精湛的解释...我对螺旋锁我有疑问,我可以使用螺旋锁ISR?如果没有,为什么不是 – haris 2014-03-31 17:45:04

+3

@Mecki如果我没有弄错,我相信你在回答中建议时间分片只发生在单处理器系统上。这是不正确的!您可以在单处理器系统上使用自旋锁,并且它会旋转直到其时间段到期。然后,另一个具有相同优先级的线程可以接管(就像您对多处理器系统所描述的那样)。 – fumoboy007 2014-04-08 21:44:14

+5

@ fumoboy007“它会旋转,直到它的时间量程到期” //这意味着你浪费CPU时间/电池电量绝对没有W/O任何单一的好处,这是完全鲁钝。不,我无处说,一次只切发生在单核系统,我在单核系统表示,目前* ONLY *时间分片,而有* REAL *并行OM多核系统(还时间分片,但无关紧要什么我在我的回复中写道);你也完全错过了混合自旋锁的概念,以及它为什么在单核和多核系统上运行良好。 – Mecki 2014-04-09 13:42:12

6

与Mecki的建议继续本文pthread mutex vs pthread spinlock亚历山大·桑德勒的博客,亚历克斯在Linux上显示spinlock & mutexes如何可以实现用#ifdef对其进行测试的行为。

但是,一定要采取根据你的观察,最后调用,理解为给出的例子是一个孤立的事件,您的项目需求,环境可能是完全不同的。

5

也请注意,某些环境和条件(如对调度水平> = DISPATCH级别的Windows上运行),则不能使用互斥而是自旋锁。 关于unix - 同样的事情。

这里是竞争对手stackexchange UNIX网站相当于一个问题:在调度上的Windows系统 https://unix.stackexchange.com/questions/5107/why-are-spin-locks-good-choices-in-linux-kernel-design-instead-of-something-more

信息: http://download.microsoft.com/download/e/b/a/eba1050f-a31d-436b-9281-92cdfeae4b45/IRQL_thread.doc

3

自旋锁和互斥同步机制的今天是很常见的待观察。

让我们想想自旋锁第一。

基本上它是一个忙碌的等待动作,这意味着我们必须等待指定的锁被释放,然后才能继续下一个动作。从概念上来说非常简单,但实施并非如此。例如:如果锁没有被释放,那么线程被换出并进入睡眠状态,我们应该处理它吗?当两个线程同时请求访问时如何处理同步锁定?

通常,最直观的想法是通过变量处理同步以保护关键部分。互斥体的概念是相似的,但它们仍然不同。重点介绍:CPU利用率。Spinlock消耗CPU时间来等待动作,因此,我们可以总结两者之间的差异:

在同质多核环境中,如果在临界区花费的时间比使用Spinlock小,因为我们可以减少上下文切换时间。 (单核比较并不重要,因为有些系统在开关中间执行Spinlock)

在Windows中,使用Spinlock会将线程升级到DISPATCH_LEVEL,在某些情况下可能不允许使用,所以这次我们必须使用互斥锁(APC_LEVEL)。

5

Mecki的回答很不错。但是,在单个处理器上,当任务正在等待中断服务例程给出的锁定时,使用螺旋锁可能有意义。中断会将控制权转移给ISR,ISR将为等待任务使用的资源做好准备。在将控制权交给被中断的任务之前,它将通过释放锁来结束。旋转任务会发现可用的螺旋锁并继续。

+2

我不确定完全同意此答案。一个单一的处理器,如果一个任务持有资源的锁,那么ISR不能安全地继续进行,并且不能等待任务解锁资源(因为持有该资源的任务被中断)。在这种情况下,任务应该简单地禁用中断来强制自身与ISR之间的排斥。当然,这必须在非常短的时间间隔内完成。 – user1202136 2016-09-24 07:29:04

-4

在单核/单CPU系统上使用自旋锁通常是没有意义的,因为只要自旋锁轮询阻塞唯一可用的CPU核心,其他线程就不能运行,因为没有其他线程可以运行,锁也不会被解锁。 IOW,自旋锁只浪费CPU时间在这些系统上没有真正的好处

这是错误的。在单处理器系统上使用自旋锁不会浪费CPU周期,因为一旦进程需要旋转锁定,禁用先占功能,因此可能没有其他人在旋转!只是使用它没有任何意义!因此,Uni系统上的自旋锁在编译时被内核取代为preempt_disable!

+0

引用的内容完全正确。如果源代码的编译结果不包含自旋锁,则引用是无关紧要的。假设你所说的内核在编译时替换了spinlock,在另一台可能或不可能是单处理器的机器上预编译时,spinlock是如何处理的,除非我们严格只在内核本身中讨论spinlock。 – Hydranix 2016-11-10 19:24:30

+0

“一旦进程发生旋转锁定,抢先被禁用”。当进程旋转时,抢先未被禁用。如果是这样的话,一个进程就可以通过输入一个螺旋锁来停止整个机器,并且永远不会离开。请注意,如果您的线程运行在内核空间(而不是用户空间)中,则采用旋转锁确实会禁用抢占,但我不认为这就是在这里讨论的内容。 – 2016-12-30 02:36:03

+0

在*编译时*由内核*? – Shien 2017-06-09 17:20:42