2011-06-28 30 views
3

我正在使用线程池(不奇怪)管理一组线程。我所试图做的是让他们对信号做的时候,我有:WaitAll和已完成事件的线程问题 - 信号触发异常

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; 
     } 
    } 

我这里有一个循环,创建一个字符数组,然后创建我的结构的填充字符数组和实例做过事件:

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(); 
} 

返回循环鳕鱼e为等待在这里:

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线程数也很有用。所以我将不得不切换到一个不同的等待模式,因为最终的应用程序将运行多一点!很多学习。

谢谢。

回答

2

有以这种方式使用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(); 
} 
+0

谢谢,我喜欢你告诉我你只能有64个线程数的事实。谢谢。 – flavour404

2

那是因为你的主要()将其与[STAThread]定义不[MTAThread]

你不能在一个STA线程使用WaitHandle.WaitAll()作为了WaitAll是一个阻塞调用,这样做是为了防止消息泵跑。这在Win32中是不允许的,在.NET中也是如此。使用WaitOne或Thread.Join之类的其他同步原语中的一个,这些原语会进行有限的抽取。

pulled from here

但是一个更好的选择是使用新Task做你想做什么。 here也是类似的例子。

+0

谢谢贾拉尔,这是一个非常难以选择谁给这一个。 – flavour404

0

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

int taskCount = 0; 

// Launch a thread 
Interlocked.Increment(ref taskCount); 

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

尝试:

foreach(ManualResetEvent doneEvent in doneEvents) 
      WaitHandle.WaitOne(doneEvent); 

    Console.WriteLine("All calculations are complete."); 
+0

这种方法会导致死锁。您必须在foreach等待循环中锁定doneEvents,并且在线程启动时您必须锁定doneEvents,并向其添加了等待句柄。 –