【问题标题】:Non-blocking I/O issue非阻塞 I/O 问题
【发布时间】:2015-01-10 14:54:35
【问题描述】:

我对套接字上的异步 I/O 没有太多经验。最近,我必须实现一个 TCP 客户端,它将在单独的线程中连接到服务器并等待输入数据,并且以非阻塞方式,以便可以通过简单地设置控制线程的一些标志变量来立即终止线程。我的解决方案是设置套接字非阻塞并实现一个循环,如果 errno 是 E_WOULDBLOCK 并在标志变量 run 不再设置时退出循环,则一遍又一遍地调用 recv。是这样的:

while(run) {
   if( -1 == recv(...))
   {
       if(errno == E_WOULDBLOCK)
            continue; 
       else
            break; 
   }
   else
   {
       process_data(...); 
   }
}

问题是:这个解决方案在 CPU 使用率方面有多好?使用 select/poll/epoll 会更有效吗?

还有一个问题:有没有办法让阻塞的select、read或connnect调用立即从其他线程返回?

【问题讨论】:

  • 语言是什么(C、C++)!?
  • 最好是:if ((errno == E_WOULDBLOCK) || (errno == EAGAIN))
  • @alk,sometimes,是的。
  • 注意,在 Linux 上,recv may block after select,因此同时使用非阻塞 IO 和选择。

标签: linux multithreading sockets unix io


【解决方案1】:

问题是:这个解决方案在 CPU 使用率方面有多好?将要 使用 select/poll/epoll 更有效?

它非常效率低下。这可能是您处理多个连接的最糟糕的方式。 考虑每个recv 是一个系统调用:它需要一个上下文切换。上下文切换并不昂贵,但是在高频循环中计算上下文切换可能会占用 CPU 使用率。 此外,如果您要在通话和另一个通话之间睡觉,以“软化循环”,您最终会在数据接收和处理之间付出延迟;人脉越多,感觉就越高。

select 基本上告诉内核:“我希望这些 fd 集由你监控,并且在发生某些事情时立即发出信号。”。您的流程将进入等待状态,并在交付事件时准备就绪。同时,CPU 可能服务于其他进程。

您可以使用阻塞多路复用器并在单独的线程(可能来自线程池)中处理每个工作,这非常有效。但这取决于你在做什么。

还有一个问题:有没有办法让阻塞的选择、读取或连接调用立即从其他线程返回?

嗯,是的。但是你想拥有什么吗?正如@alk 所说,您可以向他们发送信号。此外,对于recv 和connect,您可能需要使用select/poll 或任何其他具有超时属性的多路复用器;不过,它可能更难编程。

【讨论】:

    【解决方案2】:

    这个解决方案在 CPU 使用率方面有多好?

    忙碌的等待是非常低效的。

    使用select/poll/epoll会更有效吗?

    是的。

    有没有办法让被屏蔽的select、read 或connnect 立即返回

    是的,向阻塞的线程发送一个信号。有问题的函数将返回-1,并且errno 应设置为EINTR。在设置信号处理程序时,请注意编译器的实现如何处理 SA_RESTART。

    【讨论】:

    • 如果你不知道另一个线程所处的状态,使用信号唤醒另一个线程可能是不安全的。如果另一个线程恰好/not/被阻塞在select ,信号可能会破坏实际发生的任何事情。
    • On 可能会在进入预期阻塞的部分之前设置信号处理程序,并在离开本部分时禁用处理程序。 @user3553031
    【解决方案3】:

    您提供的代码使用紧密的轮询循环(即,在收到输入之前它不会阻塞,甚至在轮询之间等待)。由于 CPU 一直在检查输入,因此它的效率可能非常低。通常,只有在输入可用之前的最长时间受到严格限制时,这样的轮询才合适;在绝大多数情况下,您应该使用 select 或 epoll 之类的内容进行屏蔽。

    如果您有一个线程在select(或类似)上被阻塞,强制它从另一个线程恢复的一种简单方法是创建一个管道,将管道的读取端添加到选择中,然后每当您想解除阻塞选择线程时,从另一个线程写入管道。

    【讨论】:

      【解决方案4】:

      假设您使用 C 进行编程并且拥有一个不错的内核版本,pselect 是您的最佳选择。

      同时等待输入和信号是一个众所周知的问题,对于与之相关的问题和解决方案有很多很好的讨论。您可能会发现 this discussion 是一个好的开始。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-05-24
        • 1970-01-01
        • 2018-04-06
        • 2016-09-16
        • 2012-06-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多