在多个windows :: basic_handle上,WaitForMultipleObjects和boost :: asio有什么区别?

时间:2011-06-01 13:17:46

标签: c++ multithreading boost-asio waitformultipleobjects

我有一个HANDLE列表,由许多不同的IO设备控制。什么是(性能)差异:

  1. 在所有这些句柄上调用WaitForMultipleObjects
  2. async_read on boost :: windows :: basic_handle围绕所有这些句柄
  3. WaitForMultipleObjects O(n)时间是否与n的句柄数量复杂?
    你可以在Windows :: basic_handle上以某种方式调用async_read吗?或者这个假设是错误的?
    如果我在多个线程中调用同一IO设备上的运行,那么这些线程之间的处理调用是否会平衡?这将是使用asio的主要好处。

2 个答案:

答案 0 :(得分:10)

因为它听起来像你从asio派生的主要用途是它建立在IO完成端口之上(简称iocp)。那么,让我们首先将iocp与WaitForMultipleObjects()进行比较。这两种方法与Linux上的selectepoll基本相同。

iocp解决的WaitForMultipleObjects的主要缺点是无法使用许多文件描述符进行扩展。它是O(n),因为对于您收到的每个事件,您再次传入完整数组,并且内部WaitForMultipleObjects必须扫描数组以了解要触发的句柄。

然而,由于第二个缺点,这很少成为问题。 WaitForMultipleObjects()对其可以等待的最大句柄数有限制(MAXIMUM_WAIT_OBJECTS)。此限制是64个对象(请参阅winnt.h)。通过创建Event对象并将多个套接字绑定到每个事件,然后等待64个事件,可以绕过此限制。

第三个缺点是WaitForMultipleObjects()中存在一个微妙的“错误”。它返回触发事件的句柄的索引。这意味着它只能将单个事件传回给用户。这与select不同,后者将返回触发事件的所有文件描述符。 WaitForMultipleObjects扫描传入其中的句柄,并返回引发其事件的第一个句柄。

这意味着,如果您正在等待10个非常活跃的套接字,其中所有套接字在大多数情况下都有一个事件,那么对于传递到{{1的列表中的第一个套接字的服务将会有非常大的偏见}}。每次函数返回并且事件已经被服务时,可以通过超时0再次运行它来规避这一点,但这次只传递数组1的一部分超过触发的事件。重复访问所有句柄,然后使用所有句柄和实际超时返回原始调用。

iocp解决了所有这些问题,并且还引入了一个更通用的事件通知接口,非常好。

使用iocp(以及asio):

  1. 你不重复你感兴趣的句柄,你告诉windows一次,它会记住它。这意味着它可以通过许多手柄进行更好的扩展。
  2. 您没有可以等待的句柄数限制
  3. 你得到的每一个事件,即对任何特定句柄都没有偏见
  4. 我不确定您在自定义句柄上使用WaitForMultipleObjects的假设。你可能要测试一下。如果你的句柄指的是套接字,我想它会起作用。

    至于线程问题;是。如果您async_read多个线程中的run(),事件将被分派到一个空闲线程,并将随着更多线程进行扩展。这是iocp的一个特性,它甚至还有一个线程池API。

    简而言之:我认为asio或iocp可以提供比仅使用io_service更好的性能,但是这种性能是否会对您有益,主要取决于您拥有多少句柄以及它们的活跃程度。

答案 1 :(得分:1)

WaitForSingleObjectWaitForMultipleObjects都是广泛使用的函数,WaitForSingleObject函数用于等待单个线程同步对象。当对象设置为发信号或超时间隔结束时,将发出信号。如果时间间隔是无限的,它将无限期地等待。

DWORD WaitForSingleObject(
  HANDLE hHandle,
  DWORD  dwMilliseconds
);

WaitForMultipleObjects用于等待发出多个信号。在信号量线程同步对象中,当计数器归零时,该对象将不进行信号处理。自动重置事件和互斥对象在释放对象时不会被信号通知。手动重置事件确实会影响等待功能的状态。

DWORD WaitForMultipleObjects(
  DWORD        nCount,
  const HANDLE *lpHandles,
  BOOL         bWaitAll,
  DWORD        dwMilliseconds
);

如果dwMillisecondszero,则如果未用信号通知对象,则函数不会进入等待状态;否则,函数将进入等待状态。它总是立即返回。如果dwMillisecondsINFINITE,则该函数仅在信号通知对象时返回。