在所有后台线程池线程完成时得到通知

我有一个场景,当我用ThreadPool启动3..10个线程。 每个线程都完成它的工作并返回ThreadPool。 所有后台线程完成后,主线程中可以通知哪些选项?

目前我正在使用一种自行开发的方法,为每个创建的线程递增一个变量,并在后台线程即将完成时递减它。 这很好用,但如果有更好的选择,我很好奇。

除非使用Interlocked.Decrement ,否则递减变量(在线程之间)有点风险,但如果你有最后一个线程(即当它变为零)引发事件时该方法应该没问题。 请注意,它必须位于“finally”块中以避免在exception情况下丢失它(此外,您不想终止该进程)。

在“Parallel Extensions”(或使用.NET 4.0)中,您可能还会查看此处的Parallel.ForEach选项…这可能是将所有内容作为块完成的另一种方法。 无需手动观看。

试试这个: https : //bitbucket.org/nevdelap/poolguard

 using (var poolGuard = new PoolGuard()) { for (int i = 0; i < ... { ThreadPool.QueueUserWorkItem(ChildThread, poolGuard); } // Do stuff. poolGuard.WaitOne(); // Do stuff that required the child threads to have ended. void ChildThread(object state) { var poolGuard = state as PoolGuard; if (poolGuard.TryEnter()) { try { // Do stuff. } finally { poolGuard.Exit(); } } } 

可以以不同方式使用多个PoolGuard来跟踪线程何时结束,并处理池已经关闭时尚未启动的线程。

如果要等待的线程不超过64个,可以使用WaitHandle.WaitAll方法,如下所示:

 List events = new List(); for (int i = 0; i < 64; i++) { ManualResetEvent mre = new ManualResetEvent(false); ThreadPool.QueueUserWorkItem( delegate(object o) { Thread.Sleep(TimeSpan.FromMinutes(1)); ((ManualResetEvent)o).Set(); },mre); events.Add(mre); } WaitHandle.WaitAll(events.ToArray()); 

执行将等待所有ManualResetEvent设置,或者,您可以使用WaitAny方法。

WaitAny和WaitAll方法将阻止执行,但您可以简单地使用列表或链接到生成的任务的ManualResetEvents字典,以便稍后确定线程是否已完成。

目前还没有内置的方法来实现这一点 – 我发现它是使用池线程的最大麻烦之一。

正如Marc所说,这是在Parallel Extensions / .NET 4.0中修复的东西。

难道你不能给每个线程一个不同的ManualResetEvent,并在完成后分别设置事件。 然后,在主线程中,您可以等待传入的所有事件。

如果您只想知道所有工作何时完成,并且不需要更精细的信息(如您的情况那样),Marc的解决方案是最好的。

如果你想要一些线程来产生作业,而另一些线​​程要接收通知,你可以使用WaitHandle。 代码要长得多。

  int length = 10; ManualResetEvent[] waits = new ManualResetEvent[length]; for ( int i = 0; i < length; i++ ) { waits[i] = new ManualResetEvent( false ); ThreadPool.QueueUserWorkItem( (obj) => { try { } finally { waits[i].Set(); } } ); } for ( int i = 0; i < length; i++ ) { if ( !waits[i].WaitOne() ) break; } 

所写的WaitOne方法总是返回true,但我已经写了这样,让你记住一些重载将Timeout作为参数。

那么使用Semaphore,并设置一个限制,就像你的线程池一样。 有一个获取信号量的方法,在你开始你的线程时被调用,当你的线程结束时释放它,如果你占用了所有的信号量,就会引发一个事件。