代码之家  ›  专栏  ›  技术社区  ›  Navneeth

对等epoll客户端和死锁

  •  0
  • Navneeth  · 技术社区  · 7 年前

    假设对等程序使用 epoll 从多个对等方执行异步TCP读写。当然,这意味着每个文件描述符都设置为非阻塞,以允许 epoll_wait 调用并检查多个套接字。

    然而,存在一个潜在的问题。假设有两个对等点: A. B . A. 尝试将消息写入 B 但是 B 是不是很拥挤之类的 write 返回值-1,带 errno 设置为 EAGAIN . 此时, A. 打电话睡觉 epoll\u等待 .

    但请注意 B 已经被困在自己的呼叫中 epoll\u等待 . 如果 B 从未通知过 A. 的尝试向其发送消息失败,然后 B 永远不会醒来并尝试执行读取 A. 的套接字,整个过程将死锁。所以我的问题是 B 保证被通知 A. 正在尝试向其发送消息,即使 A. 放弃原来的 打电话睡觉?

    即使上面的答案是“是”,像这样的系统是否有可能因为应用层去同步而无限期地死锁?即 A. 尝试写入 B 但失败了,它就睡着了。然后 B 醒来并尝试阅读 A. ,但失败的原因是 A. 去睡觉了。等

    1 回复  |  直到 7 年前
        1
  •  2
  •   David Schwartz    7 年前

    任何协议如果有一种可能的状态,允许双方在阅读之前等待另一方阅读,那么这将是一个根本性的破坏协议。对于对等协议,通常禁止每个端仅仅因为不能写而延迟读取。

    在实现方面,通常每次调用 epoll_wait (或您发现就绪I/O的等效方式)检查程序正在使用的所有描述符上的输入。阅读是 从不 延迟,除非应用程序具有已读取的未处理数据,并且在处理该数据后立即停止延迟。在阅读之前等待网络活动通常是一个非常糟糕的主意。

    这就是典型的协议中立型TCP代理使用两个进程或两个线程的原因。您不能只从A中读取数据,然后再对B进行阻塞写入,因为您不知道B是否需要在写入之前读取。

    这也是为什么打电话 recv 具有 MSG_WAITALL 几乎总是个坏主意。另一端可能正在等待您接收它已经发送的字节,然后再发送。任何协议都不允许一方在读取任何字节之前等待发送所有字节,如果它还允许另一方在发送其余字节之前等待读取某些字节!

    推荐文章