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

问题描述 投票:5回答:2

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

  1. 在所有这些句柄上调用WaitForMultipleObjects
  2. 在所有这些句柄周围的boost :: windows :: basic_handle上的async_read

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

c++ multithreading boost-asio waitformultipleobjects
2个回答
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个非常活跃的套接字,其中所有套接字在大多数情况下都有一个事件,那么在传递给WaitForMultipleObjects的列表中为第一个套接字提供服务将会有很大的偏见。每次函数返回并且事件已经被服务时,可以通过超时0再次运行它来规避这一点,但这次只传递数组1中触发事件的部分。重复访问所有句柄,然后返回原始调用所有句柄和实际超时。

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

使用iocp(以及asio):

  1. 你没有重复你感兴趣的句柄,你告诉Windows一次,它会记住它。这意味着它可以通过许多手柄更好地扩展。
  2. 您没有可以等待的句柄数限制
  3. 你得到每一个事件,即对任何特定的句柄没有偏见

我不确定你在自定义句柄上使用async_read的假设。你可能要测试一下。如果你的句柄指的是套接字,我想它会起作用。

至于线程问题;是。如果你在多个线程中run() io_service,事件将被分派到一个免费线程,并将扩展为更多线程。这是iocp的一个特性,它甚至还有一个线程池API。

简而言之:我相信asio或iocp可以提供比仅仅使用WaitForMultipleObjects更好的性能,但是这种性能是否会让你受益主要取决于你拥有多少手柄以及它们的活跃程度。


1
投票

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

DWORD WaitForSingleObject(
  HANDLE hHandle,
  DWORD  dwMilliseconds
);

WaitForMultipleObjects用于等待发出信号的多个物体。在信号量线程同步对象中,当计数器变为零时,对象不发信号。释放对象时,自动重置事件和互斥锁不会发出信号。手动重置事件确实会影响等待功能的状态。

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

如果dwMillisecondszero,如果没有发信号通知该函数,则该函数不进入等待状态;它总是立即返回。如果dwMillisecondsINFINITE,则该函数仅在对象发出信号时返回。

© www.soinside.com 2019 - 2024. All rights reserved.