eventfd是linux的一个系统调用,为事件通知创建文件描述符。
eventfd()创建一个“eventfd对象”,这个对象能被用户空间应用用作一个事件等待/响应机制,靠内核去响应用户空间应用事件。这个对象包含一个由内核保持的无符号64位整型计数器。这个计数器由参数initval说明的值来初始化。
以下例子展示了在线程之间及fork()产生的进程之间的通信。
/* 创建线程之后主线程和子线程谁先运行是不确定的。
* 通过一个eventfd在线程之间传递数据的好处是多个线程无需上锁就可以实现同步。
* eventfd支持的最低内核版本为Linux 2.6.27,在2.6.26及之前的版本也可以使用eventfd,但是flags必须设置为0。
* 函数原型:
* #include <sys/eventfd.h>
* int eventfd(unsigned int initval, int flags);
* 参数说明:
* initval,初始化计数器的值。
* flags, EFD_NONBLOCK,设置socket为非阻塞。
* EFD_CLOEXEC,执行fork的时候,在父进程中的描述符会自动关闭,子进程中的描述符保留。
* 场景:
* eventfd可以用于同一个进程之中的线程之间的通信。
* eventfd还可以用于同亲缘关系的进程之间的通信。
* eventfd用于不同亲缘关系的进程之间通信的话需要把eventfd放在几个进程共享的共享内存中(没有测试过)。
*/
#include <stdlib.h>
#include <stdio.h>
#include <sys/eventfd.h>
#include <pthread.h>
#include <memory.h>
#include <unistd.h>
#include <errno.h>
#include <stdint.h>
int efd = -1;
//循环接收线程。
void * recv(void * pars) {
int len = -1;
uint64_t msg = 0;
printf("Thread created!\n");
while(1) {
len = read(efd, &msg, sizeof(uint64_t)); //如果计数器为0则阻塞。
printf("Current msg is %d\n", msg);
}
}
int main(int argc, char ** argv) {
pthread_t tid;
pid_t fpid;
int len = -1;
uint64_t item = 1;
int i = 0;
efd = eventfd(0, 0);
if(efd == -1) {
printf("Error! Fail to create event fd.\n");
} else {
printf("OK! Create event fd is %d\n", efd);
}
fpid = fork();
if(fpid > 0) { //父进程接收消息(父进程同时也发送消息。)
pthread_create(&tid, NULL, recv, NULL);
}
//循环发送。
while(1) {
sleep(1);
len = write(efd, &item, sizeof(uint64_t)); //如果写sizeof(unsigned int)则参数错误。必须传8。
//如果计数器达到0xfffffffe,则阻塞。
if(len != sizeof(uint64_t)) {
printf("Error! Fail to write event fd, errno: %d,errmsg: %s\n"
,errno, strerror(errno));
}else {
printf("Success to write.\n");
}
}
pthread_exit(0);
return 0;
}