“自旋锁”到底是什么?


108

我一直想知道它们是什么:每当我听到它们的声音时,类似飞轮的未来派设备的图像就会在我的脑海中飞舞(滚动?)。

这些是什么?

Answers:


125

当您使用常规锁(互斥锁,关键节等)时,操作系统会将线程置于WAIT状态,并通过在同一内核上调度其他线程来抢占该线程。如果等待时间真的很短,则会降低性能,因为您的线程现在必须等待抢占,才能再次接收CPU时间。

此外,内核对象并非在内核的每个状态下都可用,例如在中断处理程序中或分页不可用时等。

自旋锁不会引起先占,而是循环等待(“自旋”),直到另一个内核释放该锁为止。这样可以防止线程丢失其数量并在锁释放后立即继续。自旋锁的简单机制允许内核在几乎任何状态下使用它。

这就是为什么在单核计算机上,自旋锁只是一个“禁用中断”或“引发IRQL”,它完全阻止了线程调度。

自旋锁最终允许内核避免使用“大内核锁”(当内核进入内核并在出口释放时获得的锁),并且对内核基元进行粒度锁定,从而在多核计算机上实现更好的多处理,从而提高性能。

编辑:出现一个问题:“这是否意味着我应该尽可能使用自旋锁?” 我将尝试回答:

正如我提到的那样,自旋锁仅在预期的等待时间短于量子(读取:毫秒)且抢占没有多大意义(例如,内核对象不可用)的地方有用。

如果等待时间未知,或者您处于用户模式,则自旋锁效率不高。在检查自旋锁是否可用时,您在等待的内核上消耗了100%的CPU时间。您可以阻止其他线程在该核心上运行,直到您的数量到期为止。这种情况仅适用于内核级别的短脉冲,而不太可能是用户模式应用程序的选择。

这里有一个关于SO解决的问题:自旋锁,它们有多有用?


这是否意味着我应该尽可能地自旋锁定(而不是互斥锁,临界区等)?

1
如果我错了,请有人纠正我,但自旋锁不会禁用抢占(即重新计划)。原因很简单,如果自旋锁正在等待被另一个进程锁定的资源,则必须给第二个进程运行和释放资源的机会。或者,运行第二个进程需要先抢占第一个(旋转)进程。
user1284631 2012年

自旋锁所做的是,它不会将进程状态从TASK_RUNNING更改为TASK_INTERRUPTIBLE(处于睡眠状态),因此不会保存有关该进程的所有内容(内存,缓存等)。取而代之的是,旋转过程被抢占,但它从未退出“立即可调度”的过程:它保留在内存中,而其他过程则定期运行,直到其中一个过程释放了旋转器正在等待的资源:那时,自旋锁简单地返回并且旋转过程能够继续。它总是以TASK_RUNNING状态等待。
user1284631 2012年

1
您对此是正确的(另请参见:linuxjournal.com/article/5833),但事实是,锁定资源和禁用中断虽然可以一起执行,但它们在其他方面无关紧要。您基本上想确保您没有使用处于不一致状态的资源,因此这就是测试其锁定的原因。禁用中断(也可抢占)可确保是的,在您处理中断时,没有人会干扰您的中断。但是,为此,您必须确保在获取资源时该资源是免费的。
user1284631 2012年

1
(然后禁用中断只是为了确保没有其他任务会抢占您并弄乱资源)。在UP(单处理器)上,总是这样:仅授予第一个(及其后一个)自旋锁,禁用中断(即抢占),并且永远不会抢占使用资源的任务:它将执行所有任务资源,然后启用中断(并因此抢占)。启用抢占功能后,该资源已经可用。基本上,在UP上,没有自旋锁争用也没有等待。在SMP上可能是这样。
user1284631 2012年

25

假设资源受锁保护,想要访问该资源的线程需要首先获取该锁。如果该锁不可用,则线程可能会反复检查该锁是否已释放。在这段时间内,线程忙于等待,使用CPU检查锁定,但没有做任何有用的工作。这种锁称为自旋锁。


2
好答案!+1
Jayesh Bhoi '18年

18

直到满足特定条件为止,这几乎是一个循环:

while(cantGoOn) {};

1
和/或while(cantGoOn){sleep(0)};
Jiminion '16

@Jiminion如果放了sleep(0)它,它将抢占线程,从而扼杀了使用自旋锁的目的。如果需要让步给其他线程,则应该使用常规锁。(我知道您的评论很老,但想阻止其他人将其视为建议)。
塞达

“值为零将导致该线程将其时间片的其余部分放弃给其他准备运行的线程。如果没有其他准备运行的线程,该函数将立即返回,并且该线程继续执行。”
Jiminion '18年



3

自旋锁是线程等待直到锁可用之前的锁。当存在在很小的时间段内获取内核对象的范围时,这通常将用于避免获取内核对象的开销。

例如:

While(SpinCount-- && Kernel Object is not free)
{}

try acquiring Kernel object

3

当您认为进入忙碌的等待循环并集中资源而不是在资源锁定时阻塞时更便宜时,您可能想使用自旋锁。

当锁的粒度很细且数量很大时(例如,链表中的每个节点都有一个锁),以及锁的保持时间总是非常短时,旋转将是有益的。通常,在持有自旋锁的同时,应避免阻塞,调用本身可能阻塞的任何事物,一次持有多个自旋锁,进行动态调度的调用(接口和虚拟),将静态调度的调用变为任何代码都不会执行”拥有或分配内存。

同样重要的是,出于性能原因,SpinLock是一种值类型。因此,必须非常小心,不要意外地复制一个SpinLock实例,因为这两个实例(原始实例和副本)将彼此完全独立,这很可能导致应用程序的错误行为。如果必须传递SpinLock实例,则应按引用而不是按值传递它。


1

简而言之,自旋锁采用原子比较和交换(CAS)或测试设置等指令来实现无锁,无锁线程安全习惯。这样的结构在多核计算机中很好地扩展。


从定义上讲,自旋锁不用于实现任何无锁或无等待的东西。
rdb

0

这是一个循环,直到满足条件为止。


0

好吧,是的-自旋锁(相对于传统的关键部分等)的要点是,它们在某些情况下(多核系统..)提供更好的性能,因为它们不会立即产生线程余量。


0

自旋锁(Spinlock)是一种锁,它是不可阻止和不可睡眠的。任何想要为任何共享资源或关键资源获取自旋锁的线程都将连续旋转,这将浪费CPU处理周期,直到它为指定资源获取锁为止。一旦获得了自旋锁,它将尝试在其范围内完成工作,然后分别释放资源。自旋锁是具有最高优先级的锁类型,可以简单地说,它是非抢占式锁。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.