epoll 使用笔记

原文:http://my.oschina.net/pthread/blog/37711

之前用epoll都是知其然不知其所以然,很多东西还不是很了解,网上找了一大圈,精辟的多,垃圾文章更多,在此总结下,算是做个笔记,其实就以下几点,但可以想明白很多东西。

1、如果fd被注册到两个epoll中时,如果有事件发生则两个epoll都会触发事件。
2、如果注册到epoll中的fd被关闭,则其会自动被清除出epoll监听列表。
3、如果多个事件同时触发epoll,则多个事件会被联合在一起返回。
4、epoll_wait会一直监听epollhup事件发生,所以其不需要添加到events中。
5、为了避免大数据量io时,et模式下只处理一个fd,其他fd被饿死的情况发生。linux建议可以在fd联系到的结构中增加ready位,然后epoll_wait触发事件之后仅将其置位为ready模式,然后在下边轮询ready fd列表。
6、单个epoll并不能解决所有问题,特别是你的每个操作都比较费时的时候,因为epoll是串行处理的。 所以你有还是必要建立线程池来发挥更大的效能。这点其实跟第5点是一个意思,线程池是个比较常用的解决方法。 
7、将注册在epfd上的socket fd的事件类型给清空,所以如果下一个循环你还要关注这个socket fd的话,则需要用epoll_ctl(epfd,EPOLL_CTL_MOD,listenfd,&ev)来重新设置socket fd的事件类型。这时不用EPOLL_CTL_ADD,因为socket fd并未清空,只是事件类型清空。这一步非常重要。 
8、epoll_ctl 与  epoll_wait不在一个线程行吗?,如果epoll_ctl加入了一个事件,epoll_wait能立即知道吗?还是需要退出来重新开始?可以,事件立即得到响应。

在水平触发模式下,如果对端socket关闭,则会一直触发epollin事件,驱动去处理client socket。
在边沿触发模式下,如果client首先发送协议然后shutdown写端。则会触发epollin事件。但是如果处理程序只进行一次recv操作时,根据recv收取到得数据长度来判读后边是否还有需要处理的协议时,将丢失客户端关闭事件。

 在nginx中,epoll_wait时间是最快发生的事件的时间,根据上面几点就不难理解了,可以很好的解决超时问题,而varnish中直接是永远等待,因为epoll作为单独线程加超时检测线程,效率也不错。

附带epoll_create中size的问题,之前就调查过,varnish中直接设置成1

 (0)int epoll_create (int  size) ;

(0.1)函数返回一个epoll专用的描述符epfd,epfd引用了一个新的epoll机制例程(instance.)。

(0.2)参数size是这个epoll专用描述符epfd所关联的socketfd的最大个数。man手册指出:The  size  is  not  the maximum size of the backing store but just a hint to the kernel about how to dimension internal structures.  (Nowadays, size  is ignored; see NOTES below.)从2,6.8内核就不使用这个参数,而是内核动态分配所需的数据结构。

(0.3)当我们不再需要epfd时,一定要调用close关闭他。当epfd被关闭时,kernel销毁所引用的instance和释放相关资源。

正如man手册所指出的epoll_create的参数size,其实已经被抛弃了,毫无用处,但设置必须大于0。epoll_create1和epoll_create功效一样,而且还添加了一个flags参数,其值如下:

enum  {

    EPOLL_CLOEXEC = 02000000,//在新建的epfd上设置FD_CLOEXEC。

    EPOLL_NONBLOCK = 04000   //新建的epfd设置为非阻塞。

  };

 

成员events对应的值如下,他表示相应的描述符发生的事件或状态:

enum EPOLL_EVENTS

  {

    EPOLLIN = 0x001,//可读

    EPOLLPRI = 0x002,//有紧急数据可读,比如带外数据

    EPOLLOUT = 0x004,//可写

    EPOLLRDNORM = 0x040,

    EPOLLRDBAND = 0x080,

    EPOLLWRNORM = 0x100,

    EPOLLWRBAND = 0x200,

    EPOLLMSG = 0x400,

    EPOLLERR = 0x008,//出错

    EPOLLHUP = 0x010,//挂断

    EPOLLRDHUP = 0x2000,//连接断开,或处于半关闭状态(前提是对应的流socket,就是支持连接的socket)。man手册中的说明:(since Linux 2.6.17)  Stream socket peer closed connection, or shut down writing  half  of connection.  (This flag is especially useful for writing simple code to detect peer shutdown when using Edge Triggered monitoring.)

 

    EPOLLONESHOT = (1 << 30),/*默认监听一个socketfd之后并不把它从epfd关联的socketfd集合中删除,只清空socketfd对应的事件成员的值一次事件。EPOLLONESHOT表示设置socketfd为监听一次事件。当监听完这次事件之后,从epfd关联的socketfd集合中删除监听的socketfd,如果还需要继续监听这个socketfd的话,需要再次把这个socketfd加入到epfd关联的socketfd集合(队列)里 */

 

    EPOLLET = (1 << 31)// 将epfd设为边缘触发(Edge Triggered)模式,默认epfd是电平触发(Level Triggered)。 下文细述。

  };

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值