为什么是“睡觉”?持有自旋锁时不允许?

发布于 2024-12-11 14:44:26 字数 570 浏览 0 评论 0原文

可能的重复:
为什么持有自旋锁时不能睡觉?

据我所知要知道,自旋锁应该在短时间内使用,并且只能在不允许休眠(抢占)的中断处理程序等代码中选择。

但是,我不知道为什么有这样一个“规则”,即在持有自旋锁时根本不应该睡觉。我知道这不是推荐的做法(因为它对性能有害),但我认为没有理由在自旋锁中不允许睡眠。

在获取信号量时不能持有自旋锁,因为在等待信号量时可能必须休眠,并且在持有自旋锁时不能休眠(来自 Robert Love 的《Linux 内核开发》)。

我能看到的唯一原因是出于可移植性的原因,因为在单处理器中,自旋锁被实现为禁用中断,并且通过禁用中断,睡眠当然是不允许的(但睡眠不会破坏SMP系统中的代码)。

但我想知道我的推理是否正确,或者是否还有其他原因。

Possible Duplicate:
Why can't you sleep while holding spinlock?

As far as I know, spinlocks should be used in short duration, and are only choices in code such as interrupt handler where sleeping (preemption) is not allowed.

However, I do not know why there is such a "rule" that there SHOULD BE no sleeping at all while holding a spinlock. I know that it is not a recommended practice (since it is detrimental in performance), but I see no reason why sleeps SHOULD NOT be allowed in spinlocks.

You cannot hold a spin lock while you acquire a semaphore, because you might have to sleep while waiting for the semaphore, and you cannot sleep while holding a spin lock (from "Linux Kernel Development" by Robert Love).

The only reason I can see is for portability reasons, because in uniprocessors, spinlocks are implemented as disabling interrupts, and by disabling interrupts, sleeping is of course not allowed (but sleeping will not break code in SMP systems).

But I am wondering if my reasoning is correct or if there are any other reasons.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

勿挽旧人 2024-12-18 14:44:26

至少在 Linux 中,不允许在自旋锁中休眠有几个原因:

  1. 如果线程 A 在自旋锁中休眠,然后线程 B 尝试获取相同的自旋锁,则单处理器系统将发生死锁。线程 B 永远不会进入睡眠状态(因为自旋锁没有在 A 完成时唤醒 B 所需的等待列表),并且线程 A 永远不会有机会醒来。
  2. 使用自旋锁而不是信号量正是因为它们更高效 - 只要您不会长时间争用。允许睡眠意味着您将有很长的争用期,从而消除了使用自旋锁的所有好处。在这种情况下,仅使用信号量您的系统会更快。
  3. 自旋锁通常用于通过另外禁用中断来与中断处理程序同步。如果您处于睡眠状态,则此用例是不可能的(一旦进入中断处理程序,您就无法切换回线程以让它唤醒并完成其自旋锁关键部分)。

使用正确的工具完成正确的工作 - 如果您需要睡觉,信号量和互斥体就是您的朋友。

There are several reasons why, at least in Linux, sleeping in spinlocks is not allowed:

  1. If thread A sleeps in a spinlock, and thread B then tries to acquire the same spinlock, a uniprocessor system will deadlock. Thread B will never go to sleep (because spinlocks don't have the waitlist necessary to awaken B when A is done), and thread A will never get a chance to wake up.
  2. Spinlocks are used over semaphores precisely because they're more efficient - provided you do not contend for long. Allowing sleeping means that you will have long contention periods, erasing all the benefit of using a spinlock. Your system would be faster just using a semaphore in this case.
  3. Spinlocks are often used to synchronize with interrupt handlers, by additionally disabling interrupts. This use case is not possible if you sleep (once you enter the interrupt handler, you cannot switch back to the thread to let it wake up and finish its spinlock critical section).

Use the right tool for the right job - if you need to sleep, semaphores and mutexes are your friends.

糖果控 2024-12-18 14:44:26
  • 实际上,您可以在禁用中断或某种其他类型的排除活动的情况下进入睡眠状态。如果不这样做,您正在睡觉的条件可能会因中断而改变状态,然后您将永远不会醒来。如果没有提升的优先级或包含睡眠决定和上下文切换之间的执行路径的其他关键部分,睡眠代码通常永远不会被输入。

  • 但对于自旋锁来说,睡眠是一场灾难,因为锁保持设置状态。其他线程碰到它就会旋转,直到你从睡眠中醒来它们才会停止旋转。与自旋锁在最坏情况下预期的少数自旋相比,这可能是永恒的,因为自旋锁的存在只是为了同步对内存位置的访问,它们不应该与上下文切换机制交互。

    (就此而言,所有其他线程最终都可能会遇到自旋锁,然后您就会楔入整个系统每个核心的每个线程。)

  • Actually, you can sleep with interrupts disabled or some other sort of exclusion active. If you don't, the condition for which you are sleeping could change state due to an interrupt and then you would never wake up. The sleep code would normally never be entered without an elevated priority or some other critical section that encloses the execution path between the decision to sleep and the context switch.

  • But for spinlocks, sleep is a disaster, as the lock stays set. Other threads will spin when they hit it, and they won't stop spinning until you wake up from the sleep. That could be an eternity compared to the handful of spins expected in the worst case at a spinlock, because spinlocks exist just to synchronize access to memory locations, they aren't supposed to interact with the context-switching mechanism.

    (For that matter, every other thread might eventually hit the spinlock and then you would have wedged every thread of every core of the entire system.)

掩于岁月 2024-12-18 14:44:26

当您使用自旋锁时,您不能这样做,因为它应该被使用。自旋锁用于真正需要保护关键区域和共享数据结构的地方。如果您在持有信号量的同时获取一个信号量,则可以锁定对锁所附加的任何关键区域(例如,它通常是特定的较大数据结构的成员)的访问,同时允许该进程可能进入睡眠状态。例如,如果在此进程休眠时引发 IRQ,并且 IRQ 处理程序需要访问仍被锁定的关键区域,则它会被阻止,而 IRQ 永远不会发生这种情况。显然,您可以编造一些示例,其中您的自旋锁没有按应有的方式使用(例如,假设的自旋锁附加到 nop 循环);但这根本不是 Linux 内核中真正的自旋锁。

You cannot when you use a spin lock as it is meant to be used. Spin locks are used where really necessary to protect critical regions and shared data structures. If you acquire one while also holding a semaphore, you lock access to whichever critical region (say) your lock is attached to (it is typically a member of a specific larger data structure), while allowing this process to possibly be put to sleep. If, say, an IRQ is raised while this process sleeps, and the IRQ handler needs access to the critical region still locked away, it's blocked, which can never happen with IRQs. Obviously, you could make up examples where your spin lock isn't used the way it should be (a hypothetical spin lock attached to a nop loop, say); but that's simply not a real spin lock found in Linux kernels.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文