Linux中eventfd函数调用解析

eventfd 在内核版本,2.6.22以后有效。查看内核版本可以用命令 uname -r

这个函数会创建一个 事件对象 (eventfd object), 用来实现,进程(线程)间的等待/通知(wait/notify) 机制. 内核会为这个对象维护一个64位的计数器(uint64_t)。
并且使用第一个参数(initval)初始化这个计数器。调用这个函数就会返回一个新的文件描述符(event object)。2.6.27版本开始可以按位设置第二个参数(flags)。
有如下的一些宏可以使用:EFD_NONBLOCK , 功能同open(2)O_NONBLOCK,设置对象为非阻塞状态,如果没有设置这个状态的话,read(2)eventfd,并且计数器的值为0 就一直堵塞在read调用当中,要是设置了这个标志, 就会返回一个 EAGAIN 错误(errno = EAGAIN)。效果也如同 额外调用select(2)达到的效果。EFD_CLOEXEC 这个标识被设置的话,调用exec后子进程得不到这个句柄,而不影响fork产生的子进程,更多的是安全方面的考虑。

EFD_SEMAPHORE,这个标识(since Linux 2.6.30)开始,但是在Android的NDK中是没有这个定义的,因此不建议在Android中使用。他的功能完全可以用默认参数替换,而且更高效,因为如果是信号量模式,每次调用,只会减少1,导致重复进入内核,性能实际上是有影响的。

如果是2.6.26或之前版本的内核,flags 必须设置为0。

创建这个对象后,可以对其做如下操作。

write 将缓冲区写入的8字节整形值加到内核计数器上。

read 读取8字节值, 并把计数器重设为0. 如果调用read的时候计数器为0, 要是eventfd是阻塞的, read就一直阻塞在这里,否则就得到 一个EAGAIN错误。
如果buffer的长度小于8那么read会失败, 错误代码被设置成 EINVAL

poll select epoll

close 当不需要eventfd的时候可以调用close关闭, 当这个对象的所有句柄都被关闭的时候,内核会释放资源。 为什么不是close就直接释放呢, 如果调用fork 创建
进程的时候会复制这个句柄到新的进程,并继承所有的状态。

 程序实例:

运行结果:
比较简单,不做过解释。子进程写入命令行中传入的参数,父进程读取其中计数器的值。

运行结果:

命令行传入的是10、20、30其和应为60,为啥读取的是70呢?请看15行调用eventfd时第一个参数是10,这个参数是创建eventfd时初始化计数器的值。

参考链接:Linux中eventfd函数调用解析

发布者

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注