我在网上阅读文档广度边缘触发的epoll函数如下:
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. ....... .......
build议使用epoll作为边缘触发(EPOLLET)接口的方法如下:i)使用非阻塞文件描述符ii)仅在读取(2)或写入(2)返回EAGAIN之后调用epoll_wait才能发生事件。
我明白了2,但我不知道为什么使用非阻塞文件描述符。
任何人都可以解释为什么非阻塞文件描述符被使用的原因? 为什么在level触发的epoll函数中使用阻塞文件描述符是正确的?
这个想法是当你有一个边缘触发的通知,有数据要完成时,试图完全耗尽文件描述符。 所以,一旦epoll()返回,你将遍历read()或write()直到返回-EAGAIN当没有更多的数据。
如果fd被阻塞了,那么这个最后一个read()或者write()也会被阻塞,你将没有机会回到epoll()调用来等待整个fds集合。 当打开非阻塞时,最后一个read() / write()会返回,并且您有机会返回到轮询。
当以级别触发方式使用epoll()时,这并不是什么大问题,因为在这种情况下,如果有任何数据, epoll()将立即返回。 所以一个(伪代码)循环如:
while (1) { epoll(); do_read_write(); }
将会起作用,因为只要有数据,就可以保证调用do_read_write() 。 使用边缘触发的epoll时,如果在do_read_write()和下一个epoll()调用之间存在新的数据,可能会丢失新的数据。
我想这是因为边缘触发的语义。 根据语义,边缘触发器只会在收到EAGAIN后才会引发另一个事件。 在阻塞插座的情况下,没有EAGAIN。 你可以用其他方式来定义它,但这是Linux定义它的方式。 换句话说,如果你使用阻塞套接字,你不知道什么时候你可以安全地调用epoll_wait。
您必须全部读取或在epoll的ET模式下写入所有数据,因为在标志更改后et模式会触发一次。 读完所有数据后,如果使用块读取或写入,则线程必须挂起。 所以必须使用非阻塞。