我正在使用线程池(毫不奇怪)管理一组线程。我想要做的就是让他们在完成后发出信号,我有:
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数组和一个完成事件的结构实例:
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个线程计数也很有用。所以我将不得不切换到不同的等待模型,因为最终的应用程序将运行更多!有很多东西需要学习。
感谢。
答案 0 :(得分:3)
以这种方式使用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();
}
答案 1 :(得分:2)
这是因为在您的Main()中,它定义为[STAThread]
而不是[MTAThread]
您不能在STA线程上使用
WaitHandle.WaitAll()
,因为WaitAll是阻塞调用,这样做是为了防止消息泵运行。这在Win32中是不允许的,因此在.NET中也是如此。使用其他同步原语之一,如WaitOne或Thread.Join,它们可以进行有限的泵送。
然而,更好的选择是使用新的Task
来做你想做的事。 here是类似的例子。
答案 2 :(得分: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();
答案 3 :(得分:0)
尝试:
foreach(ManualResetEvent doneEvent in doneEvents)
WaitHandle.WaitOne(doneEvent);
Console.WriteLine("All calculations are complete.");