epoll的原理及用法

英文源文件来自http://linux.die.net/man/4/epoll

名字

epoll-I/O事件消息通知器

包含文件

#include <sys/epoll.h>

描述

epoll是一个poll的变种,它可以用来作为边沿或者电平触发接口,可以很好的扩展到大量的监管的fds(文件描述符)。在建立和控制一个epoll

集合的过程中会有以下三个call: epoll_create, epoll_ctl, epoll_wait.

epoll_create建立一个连接到fd的epoll set. 至于对某个特定的fds,则是通过epoll_ctl, 最后,实际的等待是通过epoll_wait启动。

札记(Note)

这个epoll的事件分布接口都可以以边沿触发(Edge Triggered ( ET ) )和电平触发( Level Triggered ( LT ))的形式表现。ET和LT事件分布

机制的区别在于以下描述的几点。假设有如下情形发生:

1. fd代表的读管道(RFD)的读被加在了epoll 设备里。

2. 管道写者写了2Kb的数据在写管道。

3. epoll_wait 的调用完成,并将返回作为就绪df的RFD。

4. 管道读者从RFD读了1Kb的数据。

5. epoll_wait的调用完成。

如果RFD已经通过使用EPOLLET flag被加入了epoll设备,在步骤5完成的epoll_wait调用将很能挂住,这是因为现有的数据仍然存在于文件输入缓冲区,而远程对等的一方可能在等待对以已经发出的数据为基础的回应。导致这样的原因是ET事件分布只对发生在被监视的文件上的事件发布事件。所以,在步骤5时,调用者可能会对已经存在输入缓冲里的一些数据停止epoll_wait。在上面的这个例子中,由于步骤2的读完成,将会产生一个RFD的事件,这个事件在步骤3会被消耗掉。由于在步骤4完成的读操作没有消耗完所有的buffer data. 在步骤5完成的epoll_wait调用可能会无限期的锁住。使用EPOLLET flag的epoll 接口将使用非阻塞式的df来避免在操作fd的任务时发生读阻塞或者写饥饿。推荐作为ET接口使用的epoll方法如下,可以避免可能的缺陷:

i  使用 non-blocking fd。

ii  待等待一个事件完成后,才读或则写。

 

相反,当使用LT(电平触发)接口时,epoll不管如何都是一个更快的poll,只要后者可以使用LT就可以用,因为他们拥有相同的语义。由于即使使用ET(边沿触发)的epoll,多块数据的接受可以激发多个事件,调用者有可以选择指定EPOLLONESHOT flag的选项,来告诉epoll在收到epoll_wait的事件后可以disable关联的df。当EPOLLONESHOT flag被指定了,重整fd将是调用者的责任,通过使用EPOLL_CTL_MOD选项。

 推荐使用的例子

struct epoll_event ev, *events;
for(;;) {
    nfds = epoll_wait(kdpfd, events, maxevents, -1);
    for(n = 0; n < nfds; ++n) {
        if(events[n].data.fd == listener) {
            client = accept(listener, (struct sockaddr *) &local,
                            &addrlen);
            if(client < 0){
                perror("accept");
                continue;
            }
            setnonblocking(client);
            ev.events = EPOLLIN | EPOLLET;
            ev.data.fd = client;
            if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, client, &ev) < 0) {
                fprintf(stderr, "epoll set insertion error: fd=%d0,
                        client);
                return -1;
            }
        }
        else
            do_use_fd(events[n].data.fd);
    }
}

  Q&A (from linux-kernel)

    Q1 : 如果往epoll_set里面添加了两次相同的fd会发生什么?

     A1:你将和可能会得到EEXIST.然后,两个线程两次添加相同的fd是可能发生的。这是一种无害情形。

     Q2:两个epoll set 可以等待相同的fd吗?如果这样,事件报告的是两个epoll sets fd 吗?

      A2:是的。但是,不推荐这么使用。是,它对两个fd都会。

      Q3:epoll fd 本身就是 poll/epoll/selectable吗?

      A3: 是的。

      Q4:  如果epoll fd被添加如到它自己的fd sets中会发生什么?

      A4: 它将会失败。但是,你可以在另外一个epoll fd sets 里添加epoll fd。

      Q5:我可以把epoll fd通过unix-socket送到另外一个进程吗?

      A5: 不行。

      Q6:关闭一个fd会导致它自动从所有的epoll sets中自动被移出来吗?

     A6: 会。

     

posted @ 2012-08-12 01:17  happydpc  阅读(475)  评论(0编辑  收藏  举报