Linux事件触发器eventfd的使⽤以及C++封装
⽂章⽬录
前⾔:为什么需要eventfd?
在我们之前的学习中,进⾏进程/线程间通信的⽅法有两个:
1. 条件变量
需要使⽤锁,线程的互斥,唤醒等机制,使⽤此⽅法来进⾏通信实在是很⿇烦;
2. 管道
管道的特点在于传送信息,并且会产⽣两个⽂件描述符,也是同样的⿇烦。
于是乎,eventfd便产⽣了,通过同⼀个⽂件描述符,能够快速的进⾏进程/线程间的通信。
eventfd 设计原理
其实简单⼀点看eventfd, 也就是⼀个普通的套接字(evfd),写端向套接字(evfd)写⼊,读端通过操作同样的套接字(evfd)就能够进⾏读取。
⼀般来说,eventfd并不是单纯的⽤来进⾏数据的读取,⽽是通过 写操作 引发 读端可读,然后引发事件。
需要包含头⽂件:#include <sys/eventfd.h>
1.int eventfd(unsigned int initval,int flags);
flags:
如果是2.6.26或之后版本的内核,flags 必须设置为0。
EFD_NONBLOCK 类似于使⽤O_NONBLOCK标志设置⽂件描述符。
EFD_CLOEXEC 类似open以O_CLOEXEC标志打开, O_CLOEXEC 应该表⽰执⾏exec()时,之前通过open()打开的⽂件描述符会⾃动关闭.
initval:
初始化计数器值,该值保存在内核, 如果设置为0,则代表还未进⾏写⼊
eventfd测试⽤例
#include<unistd.h>
#include<iostream>
#include<sys/eventfd.h>
using namespace std;
int main()
{
int evfd =eventfd(0,0);
uint64_t event_read, event_write;
if(fork())
{
sleep(1);
event_write =100;
write(evfd,&event_write,8);
cout <<"father write, event_write = "<< event_write << endl; }
else
{
read(evfd,&event_read,8);
cout <<"child read,  event_read = "<< event_read << endl; }
return0;
}
输出:
father write, event_write = 100
wwx@VM-0-7-ubuntu:~/NetworkLib$ child read,  event_read = 100
C++ 封装eventfd
Eventfd.h:
#pragma once
#include<sys/eventfd.h>
#include<functional>
using std::function;
namespace wd
{
using EventfdCallBack = function<void()>;
class Eventfd
{
public:
Eventfd(EventfdCallBack&& cb);
void start();
void stop();
void wakeup();//向_evfd中发送信息
private:
void handleRead();//读取_evfd中发送的信息
int createEventfd();
private:
int _evfd;
EventfdCallBack _cb;
bool _isRunning;
};
};
Eventfd.cpp:
#include"Eventfd.h"
#include"Eventfd.h"
#include<sys/poll.h>
#include<string.h>
#include<errno.h>
#include<unistd.h>
namespace wd
{
Eventfd::Eventfd(EventfdCallBack &&cb)
:_evfd(createEventfd()),_cb(cb),_isRunning(false)
{
}
void Eventfd::start()
{
_isRunning =true;
struct pollfd pfd;
bzero(&pfd,sizeof(pfd));
pfd.fd = _evfd;
pfd.events = POLLIN;
while(_isRunning)
{
int nready =poll(&pfd,1,5000);
if(-1== nready && errno == EINTR)
{
continue;
}
else if(-1== nready)
{
perror("poll");
}
else if(0== nready)
{
printf("timeout\n");
}
else
{
handleRead();//先读取_evfd中的数据
_cb();//再调⽤回调函数
}
}
}
void Eventfd::stop()
{
linux下的sleep函数if(_isRunning)
_isRunning =false;
}
void Eventfd::wakeup()
{
uint64_t event_write =1;
if(write(_evfd,&event_write,sizeof(uint64_t))!=sizeof(uint64_t)) {
perror("write evfd");
}
}
void Eventfd::handleRead()
{
uint64_t event_read;
if(read(_evfd,&event_read,sizeof(uint64_t))!=sizeof(uint64_t)) {
perror("read evfd");
}
}
}
int Eventfd::createEventfd() {
int evfd =eventfd(0,0);
if(-1== evfd)
{
perror("eventfd");
}
return evfd;
}
}// namespace wd

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。