为什么EventWaitHandle.WaitAny方法有64个句柄限制?

时间:2013-05-20 09:16:20

标签: c# .net multithreading

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

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

在奴隶过程中,一旦它是免费的。它将触发事件以将另一个任务与此过程相匹配。代码如:

ProxyEvent.Set()

但是,当事件的数量超过64时,它将抛出System.NotSupportedException。 检查代码来自Microsoft后,我发现它是framwork代码中的硬代码:

private const int MAX_WAITHANDLES = 64;

我的问题是:

  1. 为什么会有这样的限制?为什么64?
  2. 这个限制是否有任何工作重点?

2 个答案:

答案 0 :(得分:3)

为什么?一旦你意识到它是从WaitForMultipleObjects继承的,就可以很容易地回答。反过来,它有一个限制,因为函数的返回值试图将多个事实编码为一个整数,因此他们选择了一个适用于大多数情况的实用值。

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

使用例如TaskTPL将允许您的代码按照实际可以执行的工作量进行优雅扩展。

答案 1 :(得分:2)

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

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

变通方法根据您的目的而有所不同。例如,参见V4Vendetta提到的Workaround for the WaitHandle.WaitAll 64 handle limit?

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

(我的实际实现比上面的解释更复杂。我必须在每个数组中将等待句柄的数量限制为63,因为我需要额外的一个来阻止“其他”线程等待其中一个完成了等待阵列。)

WaitForMultipleObjects()的MSDN文档确实提到了几个解决方法:

  

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

     

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

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