在没有锁的情况下检查 list_empty

标签 c multithreading linux-kernel

我想知道 linux 内核链表的线程安全性。假设一个线程将项目添加到列表,而另一个线程读取列表。当然,在修改列表时我需要锁定/互斥锁。但是使用 list_empty 检查列表是否为空是否已经需要锁?

查看list_empty的来源:

static inline int list_empty(const struct list_head *head)
{
    return READ_ONCE(head->next) == head;
}

我们看到它使用了 READ_ONCE。据我所知,这会阻止某些编译器优化,并且对于正确对齐/大小的变量也是原子的。因为没有内存屏障,所以我无法对其他内存访问进行任何排序,但在其他线程添加项目后,列表最终会变得不为空。所以我相信锁对于 list_empty 来说并不是绝对必要的。

我问是因为我想使用 list_empty 作为 wait_event_interruptible 的条件。

最佳答案

让我们使用一些伪汇编器。

为了读取head->next,它需要读取head

mov ax, head                 (1)

然后它获取 next 的偏移量并得到 next:

mov cx, [ax+offset(next)]    (2)

现在它将它与 head 进行比较:

cmp ax,cx                    (3)

如果我们假设 head 不会改变并且不为空(例如全局变量),那么步骤 (2) 是原子的并且不需要锁。但是,如果 head 可以 更改,则第 2 步可能会获取错误数据,因为 ax 可能不再有效,例如因为调度程序暂停了步骤1之后的任务,这三个步骤必须在锁定状态下执行。

关于在没有锁的情况下检查 list_empty,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60720378/

相关文章:

mysql - 刷新线程中的查询

linux - 当你的linux内核程序出错时你采取什么方法?

c - 在结构的末尾添加 'structure identifier' 是多余的吗?它有什么用?

c - 有助于理解 C 和 C++ 中#define、const 和 enum 在汇编级别上的差异

c++ - 多线程 - 为什么在引用上工作不会改变它,而在指针上工作正常

Python:无法启动新线程。 <100 个事件线程

linux - 使用 perf 记录带参数的系统调用

linux -/proc/filesystem read 被调用三次

c++ - Fsync 太快?

c - 递归——数学公式,写程序