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后会自动关闭文件描述符,防止泄漏。
如果是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 创建
进程的时候会复制这个句柄到新的进程,并继承所有的状态。
下面是一个例子
这个API还是很有用的, 当你想要编写并发型服务器的时候,aventfd 可以完美取代 pipe去通知(唤醒)其他的进程(线程)。比如经典的异步IO reactor/selector
应用场景,去唤醒select的调用。他的缓冲区处理非常方便, 规定只有8字节。
1 #include <sys/eventfd.h>
int eventfd(unsigned int initval, int flags);
int eventfd(unsigned int initval, int flags);
这个函数会创建一个 事件对象 (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后会自动关闭文件描述符,防止泄漏。
如果是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 创建
进程的时候会复制这个句柄到新的进程,并继承所有的状态。
下面是一个例子
1
#include
<
sys
/
eventfd.h
>
2 #include < unistd.h >
3 #include < stdio.h >
4 #include < stdint.h >
5 #include < stdlib.h >
6 #include < errno.h >
7
8 #define handle_error(msg)\
9 do {perror(msg);exit( 1 );} while ( 0 )
10
11 int main( int argc, char ** argv)
12 {
13 uint64_tu;
14 ssize_ts;
15 int j;
16 if (argc < 2 ){
17 fprintf(stderr, " input<num>incommandargument " );
18 exit( 1 );
19 }
20
21 int efd;
22 if ((efd = eventfd( 0 ,EFD_NONBLOCK)) == - 1 )
23 handle_error( " eventfdfailed " );
24
25
26 switch (fork()){
27 case 0 :
28 for (j = 1 ;j < argc;j ++ ){
29 printf( " Childwriting%stoefd\n " ,argv[j]);
30
31 u = strtoull(argv[j],NULL, 0 ); /* analogesly atoi */
32 s = write(efd, & u, sizeof (uint64_t)); /* append u to counter */
33 if (s != sizeof (uint64_t))
34 handle_error( " writeefdfailed " );
35
36 }
37 printf( " childcompletedwriteloop\n " );
38
39 exit( 0 );
40 default :
41 sleep( 2 );
42
43 printf( " parentabouttoread\n " );
44 s = read(efd, & u, sizeof (uint64_t));
45 if (s != sizeof (uint64_t)){
46 if (errno = EAGAIN){
47 printf( " Parentreadvalue%d\n " ,s);
48 return 1 ;
49 }
50 handle_error( " parentreadfailed " );
51 }
52 printf( " parentread%d,%llu(0x%llx)fromefd\n " ,
53 s,(unsigned long long )u,(unsigned long long )u);
54 exit( 0 );
55
56 case - 1 :
57 handle_error( " fork " );
58 }
59 return 0 ;
60 }
2 #include < unistd.h >
3 #include < stdio.h >
4 #include < stdint.h >
5 #include < stdlib.h >
6 #include < errno.h >
7
8 #define handle_error(msg)\
9 do {perror(msg);exit( 1 );} while ( 0 )
10
11 int main( int argc, char ** argv)
12 {
13 uint64_tu;
14 ssize_ts;
15 int j;
16 if (argc < 2 ){
17 fprintf(stderr, " input<num>incommandargument " );
18 exit( 1 );
19 }
20
21 int efd;
22 if ((efd = eventfd( 0 ,EFD_NONBLOCK)) == - 1 )
23 handle_error( " eventfdfailed " );
24
25
26 switch (fork()){
27 case 0 :
28 for (j = 1 ;j < argc;j ++ ){
29 printf( " Childwriting%stoefd\n " ,argv[j]);
30
31 u = strtoull(argv[j],NULL, 0 ); /* analogesly atoi */
32 s = write(efd, & u, sizeof (uint64_t)); /* append u to counter */
33 if (s != sizeof (uint64_t))
34 handle_error( " writeefdfailed " );
35
36 }
37 printf( " childcompletedwriteloop\n " );
38
39 exit( 0 );
40 default :
41 sleep( 2 );
42
43 printf( " parentabouttoread\n " );
44 s = read(efd, & u, sizeof (uint64_t));
45 if (s != sizeof (uint64_t)){
46 if (errno = EAGAIN){
47 printf( " Parentreadvalue%d\n " ,s);
48 return 1 ;
49 }
50 handle_error( " parentreadfailed " );
51 }
52 printf( " parentread%d,%llu(0x%llx)fromefd\n " ,
53 s,(unsigned long long )u,(unsigned long long )u);
54 exit( 0 );
55
56 case - 1 :
57 handle_error( " fork " );
58 }
59 return 0 ;
60 }
这个API还是很有用的, 当你想要编写并发型服务器的时候,aventfd 可以完美取代 pipe去通知(唤醒)其他的进程(线程)。比如经典的异步IO reactor/selector
应用场景,去唤醒select的调用。他的缓冲区处理非常方便, 规定只有8字节。