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函数调用解析