WaitAll和done事件的线程问题 – 信号触发exception

我正在使用线程池(毫不奇怪)管理一组线程。 我要做的是让他们在完成后发出信号,我有:

ManualResetEvent[] doneEvents = new ManualResetEvent[char_set.Length]; public struct string_char { public string[] _str_char; public ManualResetEvent _doneEvent; public string_char(string[] str_char, ManualResetEvent doneEvent) { _str_char = str_char; _doneEvent = doneEvent; } } 

我有一个循环,创建一个char数组,然后我创建一个我的struct实例填充char数组和一个完成事件:

 doneEvents[no_of_elements - 1] = new ManualResetEvent(false); string_char s_c = new string_char(array_holder, doneEvents[no_of_elements - 1]); ThreadPool.QueueUserWorkItem(ThreadPoolCallback, s_c); 

因此,线程被创建,添加到池中,并且它快速地运行并运行,当它完成时它设置完成事件:

 public void ThreadPoolCallback(Object s_c) { string_char _s_c = (string_char)s_c; //do the calculations... //when done: _s_c._doneEvent.Set(); } 

回到主循环,代码在这里等待:

 WaitHandle.WaitAll(doneEvents); Console.WriteLine("All calculations are complete."); 

问题是我一直得到例外:

 'WaitAll for multiple handles on a STA thread is not supported.' 

我在谷歌上看了这个,但它并没有真正帮助,我做错了什么。 这基本上是ms msdn示例的重复,除了我使用结构而不是类?

我通过切换到主要的MTA(doh!)来解决问题,使用下面的建议; 了解最大值是64个线程计数也很有用。 因此,我将不得不切换到不同的等待模型,因为最终的应用程序将运行更多! 有很多东西需要学习。

谢谢。

以这种方式使用WaitHandle.WaitAll有几个问题。 你已经发现了其中一个。 另一个是它不具有很大的可扩展性,因为它有64个句柄限制。 这是我用来等待多个工作项完成的模式。 它使用CountdownEvent类。

 using (var finished = new CountdownEvent(1)) { foreach (var workItem in workItemCollection) { var captured = item; finished.AddCount(); ThreadPool.QueueUserWorkItem( (state) => { try { ProcessWorkItem(captured); } finally { finished.Signal(); } }, null); } finished.Signal(); finished.Wait(); } 

这是因为在你的Main()它用[STAThread]定义而不是[MTAThread]

您不能在STA线程上使用WaitHandle.WaitAll() ,因为WaitAll是阻塞调用,这样做是为了防止消息泵运行。 这在Win32中是不允许的,因此在.NET中也是如此。 使用其他同步原语之一,如WaitOne或Thread.Join,它们可以进行有限的抽取。

从这里拉出来

然而,更好的选择是使用新Task来做你想要的。 是类似的例子。

标记您的线程MTA(假设它不是必须是STA的UI线程)或使用不同的等待机制。 例如,您可以使用一个等待句柄,任务计数:

 int taskCount = 0; // Launch a thread Interlocked.Increment(ref taskCount); // A thread terminates if (Interlocked.Decrement(ref taskCount) == 0) doneEvent.Set(); 

尝试:

  foreach(ManualResetEvent doneEvent in doneEvents) WaitHandle.WaitOne(doneEvent); Console.WriteLine("All calculations are complete.");