MENU

linux进程通信eventfd

前言

在muduo网络应用框架中EventLoop类中学习到关于eventfd,所以系统性查找资料学习有关eventfd。

知识点

eventfd通过一个进程间共享的64位计数器来实现进程间的通信,基于事件驱动实现的轻量级进程间通信的系统调用。

int eventfd(unsigned int initval, int flags);
# 返回一个新的文件描述符,该描述符可以用于引用eventfd对象。
  • initval:初始化计数器的值。
  • flags:有三个取值。(在2.6.26版本以下的Linux,flags未使用情况下必须为0)
    • EFD_CLOEXEC:在执行fork子进程的时候一般情况会把父进程的文件描述符复制,而使用该参数可以避免这个问题。
    • EFD_NONBLOCK:设置非阻塞。如果没有该参数read操作会一直阻塞到计数器中有值,相反直接返回-1。
    • EFD_SEMAPHORE:在Linux2.6.30内核后支持,每次read计数器会减一。

read:读取成功返回8字节int型整数,如果缓冲区大小小于8字节则返回EINVAL错误。
write:将缓冲区写入8字节int型整数累加到计数器中,可以存储在计数器中的最大值是最大的无符号64位值减去1(即0xfffffffffffffffe)

结合EPOLL实现通信

#include <iostream>
#include <sys/eventfd.h>
#include <sys/epoll.h>
#include <unistd.h>

#define MAXEVENTS 1024
#define EPOLLWAIT_TIME 10000

int createEventfd() {
    int evtfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
    if (evtfd < 0) {
        abort();
    }
    return evtfd;
}

int main(int argc, char *argv[]) {

    int evtfd = createEventfd();
    int epollfd = epoll_create(MAXEVENTS);

    struct epoll_event event;
    event.data.fd = evtfd;
    // 监听可读事件&ET边缘触发
    event.events = EPOLLIN | EPOLLET;

    int ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, evtfd, &event);

    if (ret < 0) {
        std::cout << "create epoll add event fail" << std::endl;
        abort();
    }

    // fork 子进程
    int pid = fork();

    // 父进程
    if (pid > 0) {
        struct epoll_event events[MAXEVENTS];

        // 监听事件发生
        int nfds = epoll_wait(epollfd, events, MAXEVENTS, EPOLLWAIT_TIME);
        for (int i = 0; i < nfds; ++i) {
            if ((events[i].data.fd == evtfd) && (events[0].events & EPOLLIN)) {
                eventfd_t res;
                read(events[i].data.fd, &res, sizeof(eventfd_t));
                std::cout << "parent read is: " << res << std::endl;
            }
        }
        close(evtfd);
        close(epollfd);
    }
        // 子进程
    else if (pid == 0) {
        std::cout << "child sleep 3s" << std::endl;
        sleep(3);

        //向eventfd计数器写入
        eventfd_t num = 2;
        if (write(evtfd, &num, sizeof(eventfd_t)) == sizeof(eventfd_t)) {
            std::cout << "child write succ" << std::endl;
        }
        close(evtfd);
    }

    return 0;
}
返回文章列表 文章二维码 打赏
本页链接的二维码
打赏二维码