Linux的epoll使用LT+非阻塞IO和ET+非阻塞IO区别

使用epoll是否需要将socket设置为nonblocking?
取决于你使用的触发方式, 如果你使用水平触发(Level-triggered) 那么此时的epoll相当于高级的select, 你的论述是对的, 是不需要一定将socket设置为非阻塞的; 然而, 当你使用边缘触发(Edge-triggered) 那么此时从业务的完整性考虑, 是建议将socket设置为nonbocking模式, 并且在读写触发EAGAIN之后再进行epoll_wait.

来解释一下水平触发和边缘触发, 类似于数字电路当中的电位水平, 从低电平到高电平的瞬间触发动作叫边缘触发, 而处于高电平触发动作叫做水平触发。

想象这样一个场景:
有一个pipe描述符 fd 按顺序发生了如下的动作:
1. 读端的 fd 被注册到一个epoll的描述符当中, 监听读信号, 此时pipe中没有消息, 无论是边缘触发还是水平触发此刻都不会被触发
2. fd 的写端被写入2kb数据
3. 读端调用epoll_wait, 返回 fd, 此刻pipe中有2kb数据, 并且从不可读变为可读, 所以边缘触发和水平触发都会返回
4. 读端读取1kb的数据
5. 读端继续调用epoll_wait

在第五步的时候, 边缘触发和水平触发的差异就显现出来了, 此时pipe中仍然有数据,所以水平触发的epoll会立刻返回, 但是边缘触发的epoll_wait 并不会返回, 因为此时pipe一直可读, 并没有从不可读变为可读状态

所以这里就会出现一个问题, 如果写端在等读端处理完数据返回, 而读端却在等写端的2kb数据中的另外1kb, 双方就会产生死锁。 因此, 在使用边缘触发的时候, 建议将描述符设置为nonblocking, 并且在read/write产生EAGAIN的错误之后再使用epoll_wait

这也是为什么文档中:
An application that employs the EPOLLET flag should use nonblocking file descriptors to avoid having a blocking read or write starve
使用了should 而没有使用 must, 从业务的完整性来说, 为了让每次边缘触发的消息都被完整的解读, 需要使用nonblocking的描述符 并read/write 直到 EAGAIN

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值