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个线程计数。谢谢,谢谢贾拉尔,这也是一个非常困难的选择。