2

我有一个需要控制许多从属进程来完成任务的应用程序。并且有一个匹配线程来完成匹配工作。我使用 EventWaitHandle 在它们之间进行通信,在空闲时间匹配线程等待从机的事件,代码如下:

EventWaitHandle.WaitAny(GetWaitEvents());
//GetWaitEvents method will return all slave process's EventWaitHandle

在从属进程中,一旦它是空闲的。它将触发事件以将另一个任务与此进程匹配。代码如:

ProxyEvent.Set()

但是,当事件数量超过 64 时,会抛出 System.NotSupportedException。在检查了从Microsoft获取的代码后,我发现它是框架代码中的硬代码:

private const int MAX_WAITHANDLES = 64;

我的问题是:

  1. 为什么会有这样的限制?为什么是64?
  2. 这个限制有什么解决方法吗?
4

2 回答 2

3

64 的原因是 64 位处理器上一个字的位数。

该实现使用位标志使其尽可能快。

解决方法因您要执行的操作而异。例如,请参阅WaitHandle.WaitAll 64 句柄限制的解决方法?如V4Vendetta所述。

我使用的一种解决方法是将等待句柄拆分为两个数组,然后使用一个线程等待其中一个数组,另一个线程等待另一个。然后主线程等待这些线程中的任何一个。但这不是很好,因为它使用了整个额外的线程。

(我的实际实现比上面的解释更复杂。我不得不将每个数组中的等待句柄数限制为 63 个,因为当其中一个完成等待时,我需要额外的一个来停止“其他”线程等待数组。)

MSDN 文档WaitForMultipleObjects()确实提到了一些解决方法:

创建一个线程以等待 MAXIMUM_WAIT_OBJECTS 句柄,然后在该线程和其他句柄上等待。使用此技术将句柄分成 MAXIMUM_WAIT_OBJECTS 组。

调用 RegisterWaitForSingleObject 以等待每个句柄。线程池中的等待线程等待 MAXIMUM_WAIT_OBJECTS 注册对象,并在对象发出信号或超时间隔到期后分配一个工作线程。

(我过去使用第一种方法,但我早就重写了该代码以使用 IO 完成端口。)

于 2013-05-20T09:22:17.507 回答
3

为什么?一旦您意识到它是继承自WaitForMultipleObjects. 反过来,它也有一个限制,因为函数的返回值试图将多个事实编码为一个整数,因此他们选择了一个可以适应大多数情况的实用值。

我同意@Pako 的评论——运行(超过)64 个线程很可能不是最好的方法——如果它们都处于活动状态并且你的内核少于 64 个,那么你可能会淹没系统当它可以执行有用的工作时,它会浪费时间执行上下文切换。

使用 eg Tasks 或TPL将允许您的代码随其实际执行的工作量而优雅地扩展。

于 2013-05-20T09:29:20.367 回答