这几天在看eventfd,正好做一下笔记,复习的时候还可以参考下。
简介
eventfd包含一个由内核维护的64位无符号整型计数器,创建eventfd时会返回一个文件描述符,进程可以通过对这个文件描述符进行read/write来读取/改变计数器的值,从而实现进程间通信。
eventfd的创建
通过eventfd函数,来创建eventfd,该函数会返回eventfd所对应的文件描述符,函数定义如下
#include <sys/eventfd.h>
int eventfd(unsigned int initval, int flags);
参数initval:创建eventfd时初始值;
参数flags:eventfd文件描述符的标志,有下面三个:
EFD_CLOEXEC:表示eventfd在exec其他程序时会自动关闭这个文件描述符
EFD_NONBLOCK:表示eventfd非阻塞
EFD_SEMAPHORE:表示eventfd作为一个信号量来使用
返回值:成功时,返回一个非负整数的文件描述符,失败时,返回-1
eventfd的写
通过eventfd_write来进行写入操作,函数定义如下
typedef uint64_t eventfd_t;
int eventfd_write(int fd, eventfd_t value);
参数fd:是eventfd函数创建返回的文件描述符
参数value:要写入的值
返回值:0表示成功,-1表示失败
eventfd的读
通过eventfd_read来进行读操作,函数定义如下
typedef uint64_t eventfd_t;
int eventfd_read(int fd, eventfd_t *value);
和写入操作差不多,不过value是我们提前分配好,把内存地址传过去。
简单例子
例子1,实现写入和读取的基本操作
#include<sys/eventfd.h>
#include<stdio.h>
int main(int argc,char* argv[]){
int fd,write_ret,read_ret;
uint64_t value;
//初始值为1
//在Linux 2.6.26版本之前,flags参数是未使用的,并且必须指定为零
fd = eventfd(1,EFD_NONBLOCK);
if(fd ==-1){
printf("eventfd create failed\n");
return 0;
}
write_ret = eventfd_write(fd,20);
write_ret = eventfd_write(fd,30);
if(write_ret == -1){
printf("eventfd write failed\n");
return 0;
}
read_ret = eventfd_read(fd,&value);
if(read_ret == -1){
printf("eventfd read failed\n");
return 0;
}
printf("value %ld\n",value);
//read_ret = eventfd_read(fd,&value); //此代码会阻塞
//printf("value %ld\n",value);
return 0;
}
在代码中我进行了两次写入操作,最后读出的结果为51,可以看出在写入时,会把每次的写入结果还有初始值进行累加处理,
使用eventfd_read进行读取,读完后在进行读操作会阻塞直到新的数据写入。当设置flags为EFD_NONBLOCK,在进行读取才操作会直接返回失败,不会阻塞。
例子2,父进程每隔1秒写入一次数据,子进程读取数据
#include<sys/eventfd.h>
#include<sys/types.h>
#include<stdio.h>
#include<unistd.h>
int main(int argc,char* argv[]){
int fd,read_ret,write_ret;
uint64_t value;
pid_t pid;
//初始值为1
//在Linux 2.6.26版本之前,flags参数是未使用的,并且必须指定为零
fd = eventfd(1,0);
if(fd ==-1){
printf("eventfd create failed\n");
return 0;
}
pid = fork();
if(pid < 0){
printf("fork error\n");
}else if(pid == 0){
while(1){
read_ret = eventfd_read(fd,&value);
if(read_ret == -1){
printf("eventfd read failed\n");
return 0;
}
printf("value %ld\n",value);
}
}else{
while(1){
write_ret = eventfd_write(fd,20);
if(write_ret == -1){
printf("eventfd write failed\n");
return 0;
}
sleep(1); //睡眠1秒
}
}
return 0;
}
//输出结果
//value 21
//value 20
//value 20
//...