Linux eventfd 的初始值及其在可轮询锁中的应用

2 投票
1 回答
1352 浏览
提问于 2025-04-17 02:29

问题

eventfd() 是一个在 Linux 2.6.22 版本后新增的系统调用。它的调用方式是

int eventfd(unsigned int initval, int flags);

我正在利用这个调用来构建一个可以在轮询循环中使用的 新光剑Lock 类。

Python 的 Lock 对象一开始是处于未锁定状态的。我的使用方式要求初始值必须是非零的。如果这个值在内部是一个 uint64_t

这个对象包含一个由内核维护的无符号 64 位整数 (uint64_t) 计数器。

那么为什么初始值的类型是 unsigned int 呢?

详细说明

如果我使用非零值作为 未锁定 状态的 Lock,那么释放操作是通过写入来完成的。如果没有进行获取就进行多次释放,这样是错误的,需要失败。这就要求在事件对象的值为非零时,写入操作应该失败。在默认模式下,事件对象会将写入的值累加到 (uint64_t)0xfffffffffffffffe,然后才会阻止写入调用。为了检测这种情况,我会进行一个非阻塞的写入,试图将值推到这个最大值之上,从而触发这种情况:

如果加法会导致计数器的值超过最大值,那么 write(2) 要么会阻塞,直到对文件描述符执行 read(2),要么在文件描述符被设置为非阻塞时失败,并返回错误 EAGAIN。

1 个回答

1

如果我理解得没错,你是想让这个东西的状态在 0UINT64_MAX-1 之间交替变化,对吧?

最开始的值类型可能只是出于历史原因而存在。一旦使用了这样的接口,就很难再去改变它了。

如果你需要这个值一开始就是 UINT64_MAX-1,那为什么不先用 eventfd 调用一个 0 的参数,然后紧接着再用 write 写入 UINT64_MAX-1 呢?这样在把文件描述符传给其他人之前就可以完成了:

int ev = eventfd(0, 0);
write(ev, &(uint64_t const){ UINT64_MAX-1 }, sizeof(uint64_t));

(当然,你会加上错误检查的代码,对吧)

撰写回答