假设一个点对点程序使用epoll
来执行异步TCP读取和写入多个对等点。当然,这意味着每个文件描述符都设置为非阻塞,以允许调用epoll_wait
并检查多个套接字。
然而,存在潜在问题。假设有两个对等体: A 和 B 。 A 尝试将邮件写入 B ,但 B 会出现拥塞或其他情况,因此对write
的调用将返回-1 errno
设置为EAGAIN
。此时, A 会在调用epoll_wait
时进入休眠状态。
但请注意 B 已经停留在对epoll_wait
的调用上。如果 B 从未收到有关 A 尝试向其发送消息失败的通知,则 B 将永远不会唤醒并尝试在 A 的套接字上执行读取,整个事情将会死锁。所以我的问题是, B 保证会收到 A 尝试向其发送消息的通知,即使 A 放弃原始{ {1}}打电话进去睡觉?
即使上面的答案是"是",由于应用层失步,这样的系统是否有可能无限期地死锁?即 A 尝试写入 B 但失败,因此进入睡眠状态。然后 B 醒来并尝试从 A 读取,但由于 A 进入睡眠状态而失败。等
答案 0 :(得分:2)
任何具有可能状态的协议都允许双方在读取之前等待另一方阅读,这将是一个根本破坏的协议。对于对等协议,通常禁止每一端因为无法写入而延迟读取。
在实现方面,通常每次调用epoll_wait
(或发现就绪I / O的等效方式)都会检查程序正在使用的所有描述符的输入。除非应用程序具有已读取的未处理数据,否则读取永远不会延迟,并且只要处理完数据就会停止延迟。在阅读之前等待网络活动通常是一个非常糟糕的主意。
这就是典型的协议中立TCP代理使用两个进程或两个线程的原因。你不能只是从A读取然后对B进行阻塞写入,因为你不知道B在写入之前是否需要读取。
这也是为什么用recv
调用MSG_WAITALL
几乎总是一个坏主意。另一端可能正在等待您在发送之前接收已发送的字节。没有协议可以允许一方在读取其中任何字节之前等待所有字节发送,如果它还允许另一方等待直到读取一些字节,然后再发送其余字节!