8

当编写一个非阻塞程序(处理多个套接字)时,它在某个时候需要使用 open(2)、stat(2) 文件打开文件或使用 opendir(2) 打开目录,我如何确保系统调用执行不阻塞?

对我来说,似乎除了使用线程或 fork(2) 之外别无选择。

4

3 回答 3

4

正如 Mel Nicholson 回答的那样,对于基于文件描述符的所有内容,您都可以使用select / poll / epoll。对于其他所有事情,您都可以拥有一个带有小堆栈的代理线程(或线程池),该堆栈将(通过内核调度程序)将任何同步阻塞等待转换为使用eventfd的 select/poll/epoll-able 异步事件或unix 管道(需要可移植性)。

代理线程将阻塞直到操作完成,然后写入 eventfd 或管道以唤醒 select/poll/epoll。

于 2013-01-08T08:21:06.523 回答
2

确实没有其他方法。

实际上,还有另一种阻塞是线程无法处理的,那就是页面错误。这些可能发生在程序代码、程序数据、内存分配或从文件映射的数据中。避免它们几乎是不可能的(实际上您可以将一些页面锁定到内存中,但这是特权操作,并且可能会使内核在其他地方的内存管理工作不佳而适得其反)。所以:

  1. 您不能真正消除阻止特定客户端的每一个最后机会,所以不要理会openand之类的东西stat。无论如何,网络可能会增加比这些功能更大的延迟。
  2. 为了获得最佳性能,您应该有足够的线程,以便在其他线程因页面错误或类似的困难阻塞点阻塞时可以安排一些线程。

此外,如果您需要在处理网络请求期间读取和处理或处理和写入数据,使用内存映射访问文件会更快,但这是阻塞的,不能设为非阻塞。因此,现代网络服务器倾向于坚持对大多数内容的阻塞调用,并且只需有足够的线程来保持 CPU 忙碌,而其他线程正在等待 I/O。

大多数现代服务器都是多核的这一事实是您无论如何都需要多个线程的另一个原因。

于 2013-01-08T08:30:03.737 回答
0

您可以使用该poll( )命令使用单个线程检查任意数量的套接字中的数据。

有关 linux 的详细信息,或man poll有关您的系统的详细信息,请参见此处。

open( )并且stat( )将阻塞在所有符合 POSIX 的系统中调用它们的线程,除非通过异步策略调用(如在 a 中fork

于 2013-01-08T08:14:12.560 回答