Skip to content

EPOLL

基于fd epoll的定时器提前唤醒

  • 在epollFd的监听fd上新建一个awakenFd,当定时器被用户手动关闭时(ShutDown),调用write系统函数在awakenFd上发送任意信息,触发epoll_wait 的返回(而不是等待设定的超市时间后才返回),在epoll_wait返回后,会收到awakenFd发送的任意信息,进行read读取后,即可提前解除epoll_wait的阻塞

  • 同样可以用于提前结束有超时的epoll监听

    C++
    # include <sys/epoll.h>
    # include <sys/eventfd.h>
    
    // 1. 启动时,在epollFd_上添加awakenFd监听
    if (epollFd_ < 0) {
        epollFd_= epoll_create1(EPOLL_CLOEXEC);
    }
    
    if (awakenFd_< 0) {
        awakenFd_ = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
        if (awakenFd_ < 0) {
            std::cerr << "Failed to create awakenFd\n";
            return;
        }
    }
    
    struct epoll_event epollEvent = {
        .events = EPOLLIN | EPOLLET,
        .data   = {.fd = awakenFd_},
    };
    
    epoll_ctl(epollFd_, EPOLL_CTL_ADD, awakenFd_, &epollEvent);
    
    // 2. 关闭时(ShutDown),write sth.
    static const uint64_t incre = 1;
    write(awakenFd_, &incre, sizeof(incre));
    
    // 3. 在定时器的阻塞线程中epoll_wait收到write事件时将会返回
    std::vector<struct epoll_event> epollEvents(maxEvents_);
    int nfd = epool_wait(epollFd_, &epollEvents[0], static_cast<int>(epollEvents.size()), timeout);
    
    for (int index = 0; index < nfd; ++index) {
        if (epollEvents[index].data.fd == awakenFd_) {
            uint64_t value = 0;
            read(awakenFd_, &value, sizeof(value));
            continue;
        }
        // process other common event
    }
    
    if (nfd == maxEvents_) {
        // 对maxEvents_扩容,初始值可能是8等。。
        maxEvents_ *= 2;
    }
    
    // 4. 清理该定时器时,同时清理awakenFd
    if (awakenFd_> 0) {
        close(awakenFd_);
        awakenFd_ = -1;
    }