2011-06-30 228 views
15

如果我增加就業機會與QueueUserWorkItem線程池......我怎麼把我的計劃從直到所有的作業都完成前進?等待QueueUserWorkItem來完成

我知道我可以添加一些邏輯來阻止應用程序運行,直到完成所有作業,但我想知道是否有像Thread.Join()之類的東西,或者是否有任何方法可以檢索正在分配作業的每個線程。

+0

您正在使用哪種版本的.NET? –

+0

.NET版本2.0 – PedroC88

回答

38

你可以使用事件同步。就像這樣:

private static ManualResetEvent resetEvent = new ManualResetEvent(false); 

public static void Main() 
{ 
    ThreadPool.QueueUserWorkItem(arg => DoWork()); 
    resetEvent.WaitOne(); 
} 

public static void DoWork() 
{ 
    Thread.Sleep(5000); 
    resetEvent.Set(); 
} 

如果您不想嵌入事件設置成你的方法,你可以做這樣的事情:

var resetEvent = new ManualResetEvent(false); 
ThreadPool.QueueUserWorkItem(
    arg => 
    { 
     DoWork(); 
     resetEvent.Set(); 
    }); 
resetEvent.WaitOne(); 

多個項目:

var events = new List<ManualResetEvent>(); 

foreach(var job in jobs) 
{ 
    var resetEvent = new ManualResetEvent(false); 
    ThreadPool.QueueUserWorkItem(
     arg => 
     { 
      DoWork(job); 
      resetEvent.Set(); 
     }); 
    events.Add(resetEvent); 
} 
WaitHandle.WaitAll(events.ToArray()); 
+0

這很容易在一段時間排隊一個工作努力......但如果我有多個作業,然後我需要一個扣來控制呢?我不是嗎?如果不是......這是如何適應多個排隊工作? – PedroC88

+2

@ PedroC88 - 更新了答案。 –

+1

這有64個項目的限制。正如其他答案顯示,有更多適合的結構來處理多個任務,但是如果您針對的是較早的配置文件,則可以使用單個事件並使用遞減的Interlocked.Decrement –

14

的最好的方法是使用CountdownEvent類。這是一個相當完善的模式,並且具有可擴展性。

using (var finished = new CountdownEvent(1)) 
{ 
    foreach (var workitem in workitems) 
    { 
    var capture = workitem; // Used to capture the loop variable in the lambda expression. 
    finished.AddCount(); // Indicate that there is another work item. 
    ThreadPool.QueueUserWorkItem(
     (state) => 
     { 
     try 
     { 
      ProcessWorkItem(capture); 
     } 
     finally 
     { 
      finished.Signal(); // Signal that the work item is complete. 
     } 
     }, null); 
    } 
    finished.Signal(); // Signal that queueing is complete. 
    finished.Wait(); // Wait for all work items to complete. 
} 
+0

這是一個很好的解決方案,不幸的是它只適用於。 NET 4以上。 – newprint

+0

@BrianGideon優秀的答案!但是,我怎麼能用'CountdownEvent'過早地取消線程呢?就像我在Windows窗體應用程序中使用它並且用戶關閉表單一樣,但有線程正在運行。 –

+1

@JohnOdom:這個答案有點過時了。一個更現代的解決方案是使用任務並行庫這樣的東西。無論如何,列入TPL的是合作取消班。這是應該用來優雅地終止線程的東西。 –

2

您可以使用.NET的Barrier類來實現此目的。

Barrier barrier = new Barrier(3); 
for(int i = 0; i < 2; i++) 
{ 
    ThreadPool.QueueUserWorkItem(
    (state) => 
    { 
     foo(); 
     barrier.SignalAndWait(); 
    }, null); 
} 
barrier.SignalAndWait(); 
+0

DrewR,你能否提供一個回答問題的例子? – Mike

+0

我添加了一個例子 - 注意這是一個.NET 4特性 –