2009-12-30 70 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線程可用於報告狀態的信息。使用鎖包裝詞典以保持安全。