C# WaitAll和done事件的线程问题-信号触发异常

C# WaitAll和done事件的线程问题-信号触发异常,c#,multithreading,visual-studio-2008,C#,Multithreading,Visual Studio 2008,我使用线程池(毫不奇怪)管理一组线程。我要做的是让他们发出信号,完成后,我有: ManualResetEvent[] doneEvents = new ManualResetEvent[char_set.Length]; public struct string_char { public string[] _str_char; public ManualResetEvent _doneEvent; public string_char

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

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数组,然后创建了一个填充char数组的结构实例和一个done事件:

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();
}
因此,线程被创建并添加到池中,它会愉快地运行,当它完成时,会设置“完成”事件:

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个线程也是很有用的。因此,我将不得不切换到一个不同的等待模式,因为最终的应用程序将运行几个以上!有很多东西要学

谢谢。

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

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


但是,更好的选择是使用新的
任务
执行您想要的操作。类似的例子。

要么标记线程MTA(前提是它不是必须为STA的UI线程),要么使用不同的等待机制。例如,您可以使用一个带有任务计数的等待句柄:

int taskCount = 0;

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

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


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

这种做法将导致僵局。在foreach等待循环中,您必须锁定doneEvents,在启动线程并向其添加等待句柄时,您必须锁定doneEvents。谢谢,我喜欢您通知我您只能拥有64个线程计数。谢谢,谢谢贾拉尔,这也是一个非常困难的选择。