在linux中,多路IO复用的方式有select poll epoll这几种方式。selece和poll,都不是线程安全的,而epoll是线程安全的。epoll在大并发的情况下,性能远高于selece和poll机制。

epoll C API

  • int epoll_create(int size);
  • 功能:创建epoll
  • 参数:

    • size: 从内核2.6开始,size的值已经被忽略,但是这个值必须要大于0
    • 返回值: 成功返回文件描述符,失败返回 -1, errno中含有失败的原因
  • int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

  • 功能:用于添加或者移除对目标fd的监控
  • 参数:

    • epfd:epoll_create返回的文件描述符
    • op:
      – EPOLL_CTL_ADD 和fd相关文件的添加
      – EPOLL_CTL_MOD 和fd相关文件的修改
      – EPOLL_CTL_DEL 和fd相关文件的移除
    • fd:目标文件描述符
    • event:event是和fd相关的描述 epoll_event的结构体如下
      typedef union epoll_data {
                 void        *ptr;
                 int          fd;
                 uint32_t     u32;
                 uint64_t     u64;
             } epoll_data_t;
      
             struct epoll_event {
                 uint32_t     events;      /* Epoll events */
                 epoll_data_t data;        /* User data variable */
             };
      events的可选项
      EPOLLIN   EPOLLOUT  EPOLLRDHUP等 
  • int epoll_wait(int epfd, struct epoll_event *events,
    int maxevents, int timeout);
  • 功能:等待epoll事件的发生,发生的事件保存在events中
  • 参数
    • events:存放这发生的事件
    • maxevents 最大的发生时间数
    • timeout epoll_wait超时时间
  • 返回值:发生的事件个数

epoll 实例

在代码中,监控目录下的文件的输入EPOLLIN,当时间发生后,通过fd读取相应的内容

#include <sys/epoll.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

#define DATA_MAX_LEN 500

/* usage: epoll <file1> [file2] [file3] ... */

int add_to_epoll(int fd, int epollFd)
{
    int result;
    struct epoll_event eventItem;
    memset(&eventItem, 0, sizeof(eventItem));
    eventItem.events = EPOLLIN;
    eventItem.data.fd = fd;
    result = epoll_ctl(epollFd, EPOLL_CTL_ADD, fd, &eventItem);
    return result;
}

void rm_from_epoll(int fd, int epollFd)
{
    epoll_ctl(epollFd, EPOLL_CTL_DEL, fd, NULL);
}


int main(int argc, char **argv)
{
    int mEpollFd;
    int i;
    char buf[DATA_MAX_LEN];
    static const int EPOLL_MAX_EVENTS = 16;
    struct epoll_event mPendingEventItems[EPOLL_MAX_EVENTS];

    if (argc < 2)
    {
        printf("Usage: %s <file1> [file2] [file3] ...\n", argv[0]);
        return -1;
    }

    /* epoll_create */
    mEpollFd = epoll_create(8);
    for (i = 1; i < argc; i++)   
    {
        int tmpFd = open(argv[i], O_RDWR);
        add_to_epoll(tmpFd, mEpollFd);
    }

    while (1)
    {

        int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, -1);
        for (i = 0; i < pollResult; i++)
        {
            printf("Reason: 0x%x\n", mPendingEventItems[i].events);
            int len = read(mPendingEventItems[i].data.fd, buf, DATA_MAX_LEN);
            buf[len] = '\0';
            printf("get data: %s\n", buf);

        }

    }

    return 0;
}

测试

上述代码,是一个监控的EPOLL_CTL_ADD EPOLLIN的事件,是用read的方式获取。
故创建一个管道,使用echo往管道中写,代码就能通过read进行读取
“`
mkdir tmp //创建一个临时目录
mkfifo tmp/1 tmp/2 tmp/3 //创建3个fifo
./epoll tmp/1 tmp/2 tmp/3 & //使用epoll进行监控

echo 111> tmp/1 //往管道中写数据
echo 222 >tmp/2

总结

epoll用户监控多个文件描述符fd的EPOLL_CTL_ADD 、EPOLL_CTL_MOD、和EPOLL_CTL_DEL的行为。

参考文献

IO 多路复用是什么意思?
IO多路复用之epoll总结
韦东山android输入子系统部分的内容

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐