【问题标题】:What exactly are "spin-locks"?究竟什么是“自旋锁”?
【发布时间】:2010-12-29 18:25:38
【问题描述】:

我一直想知道它们是什么:每次我听到它们时,未来派飞轮类设备的图像都会在我脑海中翩翩起舞(滚动?)......

它们是什么?

【问题讨论】:

    标签: spinlock


    【解决方案1】:

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

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

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

    这就是为什么在单核机器上,自旋锁只是“禁用中断”或“提高 IRQL”,它会完全阻止线程调度。

    自旋锁最终允许内核避免“大内核锁”(内核进入内核时获取并在退出时释放的锁)并对内核原语进行粒度锁定,从而在多核机器上实现更好的多处理,从而获得更好的性能.

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

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

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

    这是一个关于 SO 的问题:Spinlocks, How Useful Are They?

    【讨论】:

    • 这是否意味着我应该尽可能地使用自旋锁(而不是互斥锁、临界区等)?
    • 如果我错了,请有人纠正我,但自旋锁不会禁用抢占(即重新调度)。原因很简单,如果自旋锁正在等待被另一个进程锁定的资源,那么必须给第二个进程一个运行和释放资源的机会。或者,运行第二个进程需要抢占第一个(旋转)进程。
    • 自旋锁的作用是,它不会将进程状态从 TASK_RUNNING 更改为 TASK_INTERRUPTIBLE(这是一种睡眠状态),因此,它不会保存关于它的所有内容进程(内存、缓存等)。相反,旋转进程被抢占,但它永远不会退出“立即调度”进程:它保存在内存中,其他进程定期运行,直到其中一个进程释放微调器正在等待的资源:那时, spinlock 简单地返回并且旋转过程能够继续。它始终处于 TASK_RUNNING 状态。
    • 您是对的(另请参阅:linuxjournal.com/article/5833),但事实是锁定资源和禁用中断,虽然联合执行很有用,但在其他方面是不相关的概念。您基本上想确保您没有使用处于不一致状态的资源,这就是您测试其锁定的原因。禁用中断(也是抢占)确保是的,在您处理它时没有人会弄乱您的资源。但是,为此,您必须确保在获取资源时该资源是免费的。
    • (然后禁用中断以确保没有其他任务抢占您并弄乱资源)。在 UP(单处理器)上,情况总是如此:第一个(和后续的)自旋锁被简单地授予,中断(即抢占)被禁用,并且使用资源的任务永远不会被抢占:它完成所有它的与资源一起工作,然后启用中断(因此,抢占)。启用抢占后,资源已经空闲。基本上,在 UP 上,没有自旋锁争用并且没有等待。在 SMP 上可能是。
    【解决方案2】:

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

    【讨论】:

    • 不错的答案! +1
    【解决方案3】:

    这几乎是一个循环,直到满足某个条件:

    while(cantGoOn) {};
    

    【讨论】:

    • 和/或 while(cantGoOn) { sleep(0) };
    • @Jiminion 如果你放一个sleep(0),它会抢占线程,首先杀死使用自旋锁的目的。如果您需要让步给其他线程,您应该使用常规锁。 (我知道您的评论已经很老了,但想阻止其他人将此视为建议)。
    • "零值会导致线程将其剩余时间片交给任何其他准备运行的线程。如果没有其他线程准备运行,则函数立即返回,并且线程继续执行。”
    【解决方案4】:
     while(something != TRUE ){};
     // it happend
     move_on();
    

    【讨论】:

      【解决方案5】:

      这是一种锁定busy waiting

      它被认为是一种反模式,除了非常低级的驱动程序编程(调用“适当的”等待函数可能比简单地忙锁定几个周期有更多的开销)。

      参见例如Spinlocks in Linux kernel

      【讨论】:

        【解决方案6】:

        自旋锁是线程等待锁可用的锁。这通常用于避免在某个小时间段内存在获取内核对象的范围时获取内核对象的开销。

        例如:

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

        【讨论】:

          【解决方案7】:

          当您认为进入繁忙的等待循环并池化资源而不是在资源被锁定时阻塞时更便宜时,您会想要使用自旋锁。

          当锁的粒度很细且数量很大(例如,链表中的每个节点一个锁)以及锁保持时间总是极短时,自旋可能会很有用。一般来说,当持有自旋锁时,应该避免阻塞,调用任何本身可能阻塞的东西,一次持有多个自旋锁,进行动态调度调用(接口和虚拟),对任何代码进行静态调度调用t 拥有或分配内存。

          还需要注意的是,出于性能原因,SpinLock 是一种值类型。因此,必须非常小心不要意外复制 SpinLock 实例,因为这两个实例(原始实例和副本)将完全相互独立,这可能会导致应用程序的错误行为。如果 SpinLock 实例必须被传递,它应该通过引用而不是值传递。

          【讨论】:

            【解决方案8】:

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

            【讨论】:

              【解决方案9】:

              简而言之,spinlock 使用原子比较和交换 (CAS) 或类似测试和设置的指令来实现无锁、无等待线程安全习语。这种结构在多核机器中可以很好地扩展。

              【讨论】:

              • 根据定义,自旋锁不用于实现任何无锁或无等待。
              【解决方案10】:

              嗯,是的 - 自旋锁(与传统的临界区等相比)的关键在于它们在某些情况下(多核系统......)提供更好的性能,因为它们不会立即产生线程的其余部分.

              【讨论】:

                【解决方案11】:

                自旋锁,是一种锁,不可阻塞且不可休眠。任何想要为任何共享或关键资源获取自旋锁的线程都将持续自旋,浪费 CPU 处理周期,直到它获取指定资源的锁为止。一旦获得自旋锁,它会尝试在其量程内完成工作,然后分别释放资源。自旋锁是优先级最高的一种锁,简单来说,它是一种非抢占式的锁。

                【讨论】:

                  猜你喜欢
                  • 2013-06-05
                  • 2014-10-28
                  • 2012-08-27
                  • 2010-11-12
                  • 2011-03-18
                  • 2011-01-22
                  • 1970-01-01
                  相关资源
                  最近更新 更多