eventfd 在内核版本,2.6.22以后有效。查看内核版本可以用命令 uname -r。
#include <sys/eventfd.h> int eventfd(unsigned int initval, int flags);
EFD_CLOEXEC:顾名思义是在执行 exec() 调用时关闭文件描述符,防止文件描述符泄漏给子进程。
(ps:也就是说,在write之后没有read,但是又write新的数据,那么读取的是这两次的8个字节的和,在read之后再write,可以完成read和write之间的交互)
下面看一个简单的eventfd的示例:
#include <sys/eventfd.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <stdint.h> /* Definition of uint64_t */ #define handle_error(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while (0) int main(int argc, char *argv[]) { int efd = eventfd(0, 0); int j; if (efd == -1) handle_error("eventfd"); int ret = fork(); if(ret == 0) //child { for (j = 1; j < 10 ; j++) { printf("Child writing %d to efd\n", j); uint64_t one = j; ssize_t s = write(efd, &one, sizeof one); if (s != sizeof one) handle_error("write"); } printf("Child completed write loop\n"); exit(EXIT_SUCCESS); } else //parent { sleep(2); uint64_t one; ssize_t s = read(efd, &one, sizeof one); if (s != sizeof one) handle_error("read"); printf("Parent read %llu from efd\n",(unsigned long long)one); exit(EXIT_SUCCESS); } }
这个例子很简单,创建一个eventfd用于父子进程之间通信,子进程写入数据,然后父进程读取。例子并没有什么实际意义。
我们再看一个稍微复杂一点的例子,使用epoll和eventfd:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/time.h> #include <stdint.h> #include <pthread.h> #include <sys/eventfd.h> #include <sys/epoll.h> #define EPOLL_MAX_NUM 10 #define handle_error(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while (0) int efd = -1; void *read_thread(void *arg) { int ret = 0; uint64_t count = 0; int ep_fd = -1; struct epoll_event events[EPOLL_MAX_NUM]; if (efd < 0) { printf("efd not inited.\n"); return; } ep_fd = epoll_create(1024); if (ep_fd < 0) { handle_error("epoll_create fail: "); } { struct epoll_event read_event; read_event.events = EPOLLIN; read_event.data.fd = efd; //add eventfd to epoll ret = epoll_ctl(ep_fd, EPOLL_CTL_ADD, efd, &read_event); if (ret < 0) { handle_error("epoll ctl failed:"); } } while (1) { ret = epoll_wait(ep_fd, &events[0], EPOLL_MAX_NUM, -1); if (ret > 0) { int i = 0; for (; i < ret; i++) { /* if (events[i].events & EPOLLHUP) { printf("epoll eventfd has epoll hup.\n"); } else if (events[i].events & EPOLLERR) { printf("epoll eventfd has epoll error.\n"); } else */ if (events[i].events & EPOLLIN) { int event_fd = events[i].data.fd; ret = read(event_fd, &count, sizeof(count)); if (ret < 0) { handle_error("read fail:"); } else { struct timeval tv; gettimeofday(&tv, NULL); printf("success read from efd, read %d bytes(%llu) at %lds %ldus\n", ret, count, tv.tv_sec, tv.tv_usec); } } } } else if (ret == 0) { /* time out */ printf("epoll wait timed out.\n"); break; } else { handle_error("epoll wait error:"); } } } int main(int argc, char *argv[]) { pthread_t pid = 0; uint64_t count = 0; int ret,i; efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); if (efd < 0) { handle_error("eventfd failed."); } ret = pthread_create(&pid, NULL, read_thread, NULL); if (ret < 0) { handle_error("pthread create:"); } for (i = 0; i < 5; i++) { count = 4; ret = write(efd, &count, sizeof(count)); if (ret < 0) { handle_error("write event fd fail:"); } sleep(1); } printf("write_end\n"); pthread_join(pid, NULL); close(efd); return 0; }