Table of Contents

什么是eventfd

创建eventfd

读eventfd

写eventfd

使用例子


什么是eventfd

      eventfd是Linux 2.6提供的一种系统调用,它可以用来实现事件通知。eventfd包含一个由内核维护的64位无符号整型计数器,创建eventfd时会返回一个文件描述符,进程可以通过对这个文件描述符进行read/write来读取/改变计数器的值,从而实现进程间通信。

创建eventfd

       eventfd的创建是通过eventfd函数实现的,返回值即是该eventfd所对应的文件描述符,函数的原型如下所示:

       initval:创建eventfd时它所对应的64位计数器的初始值;

       flags:eventfd文件描述符的标志,可由三种选项组成:EFD_CLOEXEC、EFD_NONBLOCK和EFD_SEMAPHORE。

       EFD_CLOEXEC表示返回的eventfd文件描述符在fork后exec其他程序时会自动关闭这个文件描述符;

       EFD_NONBLOCK设置返回的eventfd非阻塞;

       EFD_SEMAPHORE表示将eventfd作为一个信号量来使用。

读eventfd

       既然eventfd是一个文件描述符,那么对其进行读取就是使用read函数了,不过对于eventfd调用read函数也有需要注意的地方,man手册有如下描述:

       从上面描述中可以知道以下几点:

       1.read函数会从eventfd对应的64位计数器中读取一个8字节的整型变量;

       2.read函数设置的接收buf的大小不能低于8个字节,否则read函数会出错,errno为EINVAL;

       3.read函数返回的值是按小端字节序的;

       4.如果eventfd设置了EFD_SEMAPHORE,那么每次read就会返回1,并且让eventfd对应的计数器减一;如果eventfd没有设置EFD_SEMAPHORE,那么每次read就会直接返回计数器中的数值,read之后计数器就会置0。不管是哪一种,当计数器为0时,如果继续read,那么read就会阻塞(如果eventfd没有设置EFD_NONBLOCK)或者返回EAGAIN错误(如果eventfd设置了EFD_NONBLOCK)。

写eventfd

       同样,对eventfd进行写操作使用的是write函数,在Man手册中也有相应的描述:

      从上面描述中可以知道:

      1.在没有设置EFD_SEMAPHORE的情况下,write函数会将发送buf中的数据写入到eventfd对应的计数器中,最大只能写入0xffffffffffffffff,否则返回EINVAL错误;

      2.在设置了EFD_SEMAPHORE的情况下,write函数相当于是向计数器中进行“添加”,比如说计数器中的值原本是2,如果write了一个3,那么计数器中的值就变成了5。如果某一次write后,计数器中的值超过了0xfffffffffffffffe(64位最大值-1),那么write就会阻塞直到另一个进程/线程从eventfd中进行了read(如果write没有设置EFD_NONBLOCK),或者返回EAGAIN错误(如果write设置了EFD_NONBLOCK)。

      除此之外,eventfd还支持select和poll,与一般的读写描述符相类似,这里就不多说了,如下所示:

使用例子

        现在写一个简单的例程,在父子进程中利用eventfd进行通信,如下所示:

#include <unistd.h>
#include <iostream>
#include <sys/wait.h>
#include <sys/eventfd.h>
#include <errno.h>
#include <stdio.h>
using namespace std;

int main()
{
	int evfd = eventfd(10,0);
	uint64_t wdata = 0;
	uint64_t rdata = 0;

	if(read(evfd,&rdata,8) == -1)
	{
		perror(NULL);
		if(errno!=EAGAIN)return 0;
	}
	cout<<"Init read : "<<rdata<<endl;  //读计数器初始值
	
	wdata = 20;
	
	if(write(evfd,&wdata,8) == -1) //父进程写20
	{
		perror(NULL);
		return 0;
	}
	cout<<"parent write : "<<wdata<<endl;
	
	if(fork() == 0)
	{
		wdata = 30;
		if(read(evfd,&rdata,8) == -1) //子进程读计数器
		{
			perror(NULL);
			return 0;
		}
		cout<<"child read : "<<rdata<<endl;
		if(write(evfd,&wdata,8) == -1)  //子进程写30
		{
			perror(NULL);
			return 0;
		}
		cout<<"child write : "<<wdata<<endl;
		exit(0);		
	}
	wait(NULL);
	if(read(evfd,&rdata,8) == -1)   //父进程读计数器
	{
			perror(NULL);
			return 0;
	}
	cout<<"parent read : "<<rdata<<endl;

	return 0;
}

运行结果如下:

GitHub 加速计划 / li / linux-dash
12
2
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e added ecosystem file for PM2 5 年前
5def40a3 Add host customization support for the NodeJS version 5 年前
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐