通俗易懂描述 epoll中的边沿触发和水平触发

epoll中两种触发模式介绍

水平触发

水平触发,就是指在条件满足时,epoll_wait函数会一直来通知你,那么什么是这个条件呢? 这个条件就是指,假如我们在epoll_wait的第一个参数,也就是红黑树的树根中,加入的都是读事件,比如下面这样的

event.events = EPOLLIN | EPOLLET;
event.data.fd = server_socket;
epoll_ctl(efd, EPOLL_CTL_ADD, server_socket, &event)

那么我们第一次没有将缓冲区中的数据全部读出,那么epoll_wait函数还会继续通知我们,上面提到的条件可以理解成 缓冲区还有东西可以读

边沿触发

就像高低电平一样,只有从高电平到低电平或者低电平到高电平时才会通知我们,还是上面这个例子,假如我们没有把数据读完,那么epoll_wait函数便不再会通知我们,因为他已经通知过了,是否把缓冲区的数据读完和epoll没关系,这时只有客户端再次向服务器端发送数据,epoll_wait才会返回

为什么一定要把边沿触发和非阻塞io一起使用呢

如果这里使用阻塞IO,那么也就是说,假如我们一次从缓冲区中读取10个字节,但是客户端只发了五个过来,那么我们的IO就会阻塞住,因为缓冲区的东西不够读,这时候其他客户端再次发送消息,epoll_wait也不会返回,因为上一次epoll_wait返回之后,代码卡在了读取这里,这样服务器就无法处理其他数据了。
但是如果使用非阻塞IO,缓冲区的数据不够读了,那就不读了,读写函数马上返回,不再等待,这样就解决了上面的问题

解决方法

参考man文档,输入man epoll
Level-triggered and edge-triggered
The epoll event distribution interface is able to behave both as edge-triggered (ET) and as level-triggered (LT). The difference between the
two mechanisms can be described as follows. Suppose that this scenario happens:

   1. The file descriptor that represents the read side of a pipe (rfd) is registered on the epoll instance.

   2. A pipe writer writes 2 kB of data on the write side of the pipe.

   3. A call to epoll_wait(2) is done that will return rfd as a ready file descriptor.

   4. The pipe reader reads 1 kB of data from rfd.

   5. A call to epoll_wait(2) is done.

   If  the  rfd  file descriptor has been added to the epoll interface using the EPOLLET (edge-triggered) flag, the call to epoll_wait(2) done in
   step 5 will probably hang despite the available data still present in the file input buffer; meanwhile the remote peer might  be  expecting  a
   response  based  on  the data it already sent.  The reason for this is that edge-triggered mode delivers events only when changes occur on the
   monitored file descriptor.  So, in step 5 the caller might end up waiting for some data that is already present inside the input  buffer.   In
   the  above example, an event on rfd will be generated because of the write done in 2 and the event is consumed in 3.  Since the read operation
   done in 4 does not consume the whole buffer data, the call to epoll_wait(2) done in step 5 might block indefinitely.

   An application that employs the EPOLLET flag should use nonblocking file descriptors to avoid having a blocking read or write  starve  a  task
   that is handling multiple file descriptors.  The suggested way to use epoll as an edge-triggered (EPOLLET) interface is as follows:

          i   with nonblocking file descriptors; and

          ii  by waiting for an event only after read(2) or write(2) return EAGAIN.(这里的EAGAIN表示缓冲区没有数据可读,或者写缓冲区已经写满了)

抛砖引玉

关于阻塞和非阻塞IO
关于边沿触发和水平触发
边沿触发为什么不能用阻塞IO

欢迎大家批评指正,共同进步

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

巴塞罗那的风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值