2010-10-13 132 views
5

如何讓前臺線程等待所有後臺(子)線程在C#中完成?我需要從隊列(數據庫)中獲取待處理作業的列表,啓動一個新線程來執行它們中的每一個,並最終等待所有子線程完成。如何在C#中做到這一點?提前致謝。如何等待所有後臺線程完成(在C#中)?

+2

可能重複的工作然後等到所有完成](http://stackoverflow.com/questions/2528907/c-spawn-multiple-threads-for-work-then-wait-until-all-finished) – 2010-10-13 13:25:33

+0

感謝所有的快速答覆我的問題 – RKP 2010-10-13 15:14:13

+0

你嘗試[EventWaitHandle();](http://msdn.microsoft.com/en-us/library/system.threading.eventwaithandle.aspx) – Bonshington 2010-10-13 13:47:13

回答

1

考慮使用線程池。你想要的大部分已經完成了。有一個example from Microsoft它幾乎完成你的整個任務。將「fibonacci」替換爲「數據庫任務」,聽起來像是你的問題。

+0

我幾分鐘前就讀過這篇文章,並即將回復說這是我正在尋找的解決方案。謝謝回覆。 – RKP 2010-10-13 15:06:50

7

您可以將每個啓動的線程存儲在一個數組中。然後當你需要等待它們全部時,在循環中的數組中的每個線程上調用Join方法。

Thread child = new Thread(...); 
Threads.Add(child); 
child.Start() 

... 

foreach(Thread t in Threads) 
{ 
    t.Join(); 
} 

HTH

+0

感謝您的答覆。我認爲thread.Join方法適用於單線程或非常少的固定線程數。對於多線程,我認爲有一個WaitAll方法,但我找不到一個好的代碼示例。 – RKP 2010-10-13 13:37:54

+3

@RKP:等待所有線程完成和等待它們一樣,不是嗎?有一個winapi函數WaitForMultipleObjects,但它不是C#,儘管你可以使用它,但我沒有看到任何意義。 – 2010-10-13 13:40:25

1

這是不完整的代碼,但ManualResetEvent爲你的作品

var waitEvents = new List<ManualResetEvent>(); 
foreach (var action in actions) 
{ 
    var evt = new ManualResetEvent(false); 
    waitEvents.Add(evt); 
    ThreadPool.RegisterWaitForSingleObject(asyncResult.AsyncWaitHandle, TimeoutCallback, state, 5000, true); 
} 

if (waitEvents.Count > 0) 
    WaitHandle.WaitAll(waitEvents.ToArray()); 
+0

謝謝,但是每個動作的新線程是從這裏開始的呢?是「5000」超時設置? – RKP 2010-10-13 13:42:31

+0

在這裏尋找完整的代碼,我只是從我之前的答案中複製了一下:http://stackoverflow.com/questions/3915017/image-url-validation-in-c/3915440#3915440 – danijels 2010-10-13 13:49:47

+0

是的,5000是超時設置 – danijels 2010-10-13 13:50:02

0

創建一個結構,讓您的工作線程的跟蹤

private struct WorkerThreadElement 
{ 
    public IAsyncResult WorkerThreadResult; 
    public AsyncActionExecution WorkerThread; 
} 

您還需要跟蹤預期要創建的線程總數以及當前有多少個線程完成

private int _TotalThreads = 0; 
private int _ThreadsHandled = 0; 
private List<WorkerThreadElement> _WorkerThreadElements = new List<WorkerThreadElement>(); 

然後創建一個自動復位句柄以等待線程完成。

// The wait handle thread construct to signal the completion of this process 
private EventWaitHandle _CompletedHandle = new AutoResetEvent(false); 

你還需要一個委託創建新主題 - 這樣做有多種方式,但我選擇了一個簡單的委託爲這個例子的目的

// Delegate to asynchronously invoke an action 
private delegate void AsyncActionExecution(); 

讓asume的Invoke方法是創建所有線程並等待其執行的入口點。所以我們有:

public void Invoke() 
{ 
    _TotalThreads = N; /* Change with the total number of threads expected */ 

    foreach (Object o in objects) 
    { 
     this.InvokeOneThread(); 
    }    

    // Wait until execution has been completed 
    _CompletedHandle.WaitOne(); 

    // Collect any exceptions thrown and bubble them up 
    foreach (WorkerThreadElement workerThreadElement in _WorkerThreadElements) 
    { 
     workerThreadElement.WorkerThread.EndInvoke(workerThreadElement.WorkerThreadResult); 
    } 
}   

InvokeOneThread是用於爲一個操作創建單個線程的方法。這裏我們需要創建一個工作線程元素並調用實際的線程。從線程完成

private void InvokeOneThread() 
{ 
    WorkerThreadElement threadElement = new WorkerThreadElement(); 
    threadElement.WorkerThread = new AsyncActionExecution(); 
    threadElement.WorkerThreadResult = threadElement.WorkerThread.BeginInvoke(actionParameters, InvokationCompleted, null); 

    _WorkerThreadElements.Add(threadElement); 
} 

回調

private object _RowLocker = new object(); 

/// <summary> 
/// Increment the number of rows that have been fully processed 
/// </summary> 
/// <param name="ar"></param> 
private void InvokationCompleted(IAsyncResult ar) 
{ 
    lock (_RowLocker) 
    { 
     _RowsHandled++; 
    } 

    if (_TotalThreads == _ThreadsHandled) 
     _CompletedHandle.Set(); 
} 

完成

1

使用動態數據,你可以通過你的對象和WaitHandle的(ActionResetEvent),讓你等待所有的後臺線程完成不宣而一個額外的類:[C#產生多個線程的

static void Main(string[] args) 
{ 
    List<AutoResetEvent> areList = new List<AutoResetEvent>(); 
    foreach (MyObject o in ListOfMyObjects) 
    { 
     AutoResetEvent are = new AutoResetEvent(false); 
     areList.Add(are); 
     ThreadPool.QueueUserWorkItem(DoWork, new { o, are }); 
    }; 

    Console.WriteLine("Time: {0}", DateTime.Now); 
    WaitHandle.WaitAll(areList.ToArray()); 
    Console.WriteLine("Time: {0}", DateTime.Now); 
    Console.ReadKey(); 
} 

static void DoWork(object state) 
{ 
    dynamic o = state; 
    MyObject myObject = (MyObject)o.o; 
    AutoResetEvent are = (AutoResetEvent)o.are; 

    myObject.Execute(); 
    are.Set(); 
}