用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线程的任务