用eventfd实现唤醒阻塞于epoll_wait的线程
eventfd是Linux提供的一个进程/线程间通信的一种方式,它是一个文件描述符,所以可以使用read/write。
在我们编写Reactor模式的服务器程序时,每个I/O线程都会有一个event loop,而这些线程会阻塞于epoll_wait(Linux系统)
我们在给这些线程分发任务时,需要唤醒阻塞这些线程,而eventfd可以加入到epoll中,所以我们可以使用eventfd来实现唤醒线程
创建eventfd
函数原型为:
int eventfd(unsigned int initval, int flags);
initval: 计数器值,在这个程序中我们只用做唤醒,所以置为0
flags: 标志位我们设置为EFD_CLOEXEC | EFD_NONBLOCK
int createEventFd() {
int fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
if (fd < 0) {
std::cout << "eventfd error" << std::endl;
exit(1);
}
return fd;
}
唤醒函数wakeUp的实现
void EventLoop::wakeUp() {
uint64_t one = 1;
write(wakeUpFd_, (char*)&one, sizeof(one));
}
readHanle回调函数
当eventfd可读时,说明用户调用了wakeUp函数
void EventLoop::readWakeUpHandle() {
std::cout << "wakeUpRead" << std::endl;
uint64_t one = 1;
read(wakeUpFd_, &one, sizeof(one));
}
将eventfd读事件加入到event loop中
wakeChannel_.setFd(wakeUpFd_);
wakeChannel_.setEvents(EPOLLIN);
wakeChannel_.setReadCallBack(std::bind(&EventLoop::readWakeUpHandle, this));
addChannel(&wakeChannel_);
将事件加入到loop中后,当线程阻塞于epoll_wait时,调用wakeUp即可实现线程的唤醒,这样线程就可以执行其他线程添加给该IO线程的任务