簡體   English   中英

如何等待所有后台線程完成(在C#中)?

[英]how to wait for all background threads to finish (in C#)?

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

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

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

...

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

HTH

這是不完整的代碼,但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());

考慮使用ThreadPool。 您想要的大部分內容已經完成。 微軟有一個例子可以完成你的整個任務。 將“fibonacci”替換為“數據庫任務”,這聽起來像是你的問題。

使用動態數據,您可以傳遞您的對象和WaitHandle(ActionResetEvent),它允許您等待所有后台線程完成而不聲明額外的類:

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();
}

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

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

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

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

然后創建一個autoreset句柄以等待線程完成。

// 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();

讓我們假設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();
}

完成

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM