【问题标题】:Avoiding sleep while holding a spinlock拿着自旋锁避免睡觉
【发布时间】:2011-04-10 06:12:51
【问题描述】:

我最近阅读了 LDDv3 书籍的5.5.2(自旋锁和原子上下文)部分:

在持有锁时避免睡眠可能会更加困难;许多内核函数可以休眠,而这种行为并不总是有据可查。将数据复制到用户空间或从用户空间复制数据就是一个明显的例子:在复制可以继续之前,可能需要从磁盘换入所需的用户空间页面,并且该操作显然需要休眠。几乎任何必须分配内存的操作都可以休眠; kmalloc 可以决定放弃处理器,并等待更多内存可用,除非明确告知不要这样做。睡眠可能发生在令人惊讶的地方;编写将在自旋锁下执行的代码需要注意您调用的每个函数

我很清楚,自旋锁必须始终保持尽可能短的时间,而且我认为从头开始编写正确的使用自旋锁的代码相对容易。

但是,假设我们有一个广泛使用自旋锁的大型项目。 我们如何确保从受自旋锁保护的关键部分调用的函数永远不会休眠?

提前致谢!

【问题讨论】:

    标签: linux-kernel sleep atomic spinlock


    【解决方案1】:

    为您的内核启用“Sleep-inside-spinlock 检查”怎么样?当您运行 make config 时,通常可以在内核调试下找到它。你也可以尝试在你的代码中复制它的行为。

    【讨论】:

    • 仅供参考,这个选项是CONFIG_DEBUG_ATOMIC_SLEEP
    【解决方案2】:

    我在很多项目中注意到的一件事是人们似乎滥用自旋锁,它们被使用而不是其他应该使用的锁定原语。

    Linux 自旋锁仅存在于多处理器构建中(在单进程构建中,自旋锁预处理器定义为空)自旋锁用于多处理器平台上的短期锁定。

    如果代码未能获得自旋锁,它只会旋转处理器,直到锁空闲。因此,在不同处理器上运行的另一个进程必须释放锁,或者它可能被中断处理程序释放,但等待事件机制是等待中断的更好方法。

    irqsave 自旋锁原语是一种禁用/启用中断的简洁方式,因此驱动程序可以锁定中断处理程序,但如果您禁用,它应该只保留足够长的时间,以便进程更新与中断处理程序共享的某些变量你不会被安排中断。

    如果您需要锁定中断处理程序,请使用带有 irqsave 的自旋锁。

    对于一般内核锁定,您应该使用互斥/信号量 api,如果需要,它将在锁上休眠。

    要锁定在其他进程中运行的代码,请使用 muxtex/semaphore 要锁定在中断上下文中运行的代码,请使用 irq save/restore 或 spinlock_irq save/restore

    要锁定其他处理器上运行的代码,请使用自旋锁并避免长时间持有锁。

    希望对你有帮助

    【讨论】:

    • 正如保罗的回答中所解释的,由于抢占,自旋锁也与单处理器系统相关。
    • spin_lock() 对具有抢占的单处理器系统也有影响:当自旋锁被锁定时,抢占被禁用。这可确保在具有抢占功能的单处理器系统中互斥。
    • 自旋锁比互斥锁/信号量更适合用于只需要对数据访问强制互斥并且不能休眠的短期锁。对于此类用途,它们比互斥体/信号量具有更高的性能。
    猜你喜欢
    • 2011-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-29
    • 2017-03-18
    • 2021-03-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多