2009-12-30 72 views
2

我有一些场景,我需要一个主线程来等待一组可能超过64个线程的每一个都完成了他们的工作,为此我写了以下帮助程序效用,(以避免上WaitHandle.WaitAll() 64 WaitHandle的极限)多线程 - 等待所有线程发信号

public static void WaitAll(WaitHandle[] handles) 
    { 
     if (handles == null) 
      throw new ArgumentNullException("handles", 
       "WaitHandle[] handles was null"); 
     foreach (WaitHandle wh in handles) wh.WaitOne(); 
    } 

在此实用程序的方法,但是,每个WaitHandle中只检查后每前一个阵列中的已用信号通知...所以它实际上是同步,并且如果等待句柄是autoResetEvent等待句柄(一旦等待线程被释放,它就会清除)将不起作用

要解决此问题,我正在考虑将此代码更改为以下内容,但希望其他人检查并查看它是否会起作用,或者如果有人看到任何问题,或者可以提供更好的方法......

在此先感谢:

public static void WaitAllParallel(WaitHandle[] handles) 
    { 
     if (handles == null) 
      throw new ArgumentNullException("handles", 
       "WaitHandle[] handles was null"); 
     int actThreadCount = handles.Length; 
     object locker = new object(); 
     foreach (WaitHandle wh in handles) 
     { 
      WaitHandle qwH = wh; 
      ThreadPool.QueueUserWorkItem(
       delegate 
       { 
        try { qwH.WaitOne(); } 
        finally { lock(locker) --actThreadCount; } 
       }); 
     } 
     while (actThreadCount > 0) Thread.Sleep(80); 
    } 
+2

您确定您需要64+个主题?这味道稍微IMHO。 – dtb 2009-12-30 21:33:59

+0

您是否可以进一步解释如何以及为什么使用AutoResetEvent?工作完成后线程是否结束? – dtb 2009-12-30 21:36:32

+0

而不是锁定对象,为什么不使用Interlocked(http://msdn.microsoft.com/en-us/library/system.threading.interlocked.aspx)类来增加和减少活动工作器的数量? – 2009-12-30 21:40:54

回答

-1
ThreadPool.QueueUserWorkItem(o => 
{ 
    try 
    { 
     using (var h = (o as WaitHandle)) 
     { 
      if (!h.WaitOne(100000)) 
      { 
       // Alert main thread of the timeout 
      } 
     } 
    } 
    finally 
    { 
     Interlocked.Decrement(ref actThreadCount); 
    } 
}, wh); 
+0

'qwH'在循环中被本地声明,所以这不是问题。 – dtb 2009-12-30 21:39:34

2

我不知道你想要做什么,但将一个CountdownEvent(.NET 4.0)概念上解决问题了吗?

3

如果您知道您有多少个线程,则可以使用互锁递减。这就是我通常做:

{ 
eventDone = new AutoResetEvent(); 
totalCount = 128; 
for(0...128) {ThreadPool.QueueUserWorkItem(ThreadWorker, ...);} 
} 

void ThreadWorker(object state) 
try 
{ 
    ... work and more work 
} 
finally 
{ 
    int runningCount = Interlocked.Decrement(ref totalCount); 
    if (0 == runningCount) 
    { 
    // This is the last thread, notify the waiters 
    eventDone.Set(); 
    } 
} 

其实,大多数时候,我甚至不发出信号,而是调用回调继续从那里服务员会继续处理。阻塞线程少,可扩展性好。

我知道是不同的,可能不适用于你的情况(例如,如果某些句柄不是线程,但I/O或事件肯定不会工作),但它可能值得考虑。

1

我不是C#或.NET程序员,但可以使用当您的其中一个工作线程退出时发布的信号量。监视线程将简单地等待信号量n次,其中n是工作线程的数量。信号量传统上用于统计正在使用的资源,但它们可用于计算通过等待n次相同信号量完成的工作。

0

在处理大量并发线程时,我更愿意在启动线程时将每个线程的ManagedThreadId添加到字典中,然后让每个线程调用一个回调例程,以从Dictionary中删除垂死线程的ID。 Dictionary的Count属性告诉你有多少线程处于活动状态。使用键/值对的值侧来保存您的UI线程可用于报告状态的信息。使用锁包装词典以保持安全。