为什么是“睡觉”?持有自旋锁时不允许?
可能的重复:
为什么持有自旋锁时不能睡觉?
据我所知要知道,自旋锁应该在短时间内使用,并且只能在不允许休眠(抢占)的中断处理程序等代码中选择。
但是,我不知道为什么有这样一个“规则”,即在持有自旋锁时根本不应该睡觉。我知道这不是推荐的做法(因为它对性能有害),但我认为没有理由在自旋锁中不允许睡眠。
在获取信号量时不能持有自旋锁,因为在等待信号量时可能必须休眠,并且在持有自旋锁时不能休眠(来自 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
至少在 Linux 中,不允许在自旋锁中休眠有几个原因:
使用正确的工具完成正确的工作 - 如果您需要睡觉,信号量和互斥体就是您的朋友。
There are several reasons why, at least in Linux, sleeping in spinlocks is not allowed:
Use the right tool for the right job - if you need to sleep, semaphores and mutexes are your friends.
实际上,您可以在禁用中断或某种其他类型的排除活动的情况下进入睡眠状态。如果不这样做,您正在睡觉的条件可能会因中断而改变状态,然后您将永远不会醒来。如果没有提升的优先级或包含睡眠决定和上下文切换之间的执行路径的其他关键部分,睡眠代码通常永远不会被输入。
但对于自旋锁来说,睡眠是一场灾难,因为锁保持设置状态。其他线程碰到它就会旋转,直到你从睡眠中醒来它们才会停止旋转。与自旋锁在最坏情况下预期的少数自旋相比,这可能是永恒的,因为自旋锁的存在只是为了同步对内存位置的访问,它们不应该与上下文切换机制交互。
(就此而言,所有其他线程最终都可能会遇到自旋锁,然后您就会楔入整个系统每个核心的每个线程。)
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.)
当您使用自旋锁时,您不能这样做,因为它应该被使用。自旋锁用于真正需要保护关键区域和共享数据结构的地方。如果您在持有信号量的同时获取一个信号量,则可以锁定对锁所附加的任何关键区域(例如,它通常是特定的较大数据结构的成员)的访问,同时允许该进程可能进入睡眠状态。例如,如果在此进程休眠时引发 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.