簡體   English   中英

C#,我怎么知道我的所有線程何時完成?

[英]C#, how do I know when all my theads have finished?

我有一個“線程” class 正在拋出執行進程的線程。 線程在線程器 class 中有一個回調方法,當它們完成時會被調用。 我的問題是我怎么知道線程器拋出的所有線程何時完成?

如果您對已啟動的線程數進行計數,您可以簡單地在線程啟動時增加計數,並在線程結束時減少計數。

然后當計數達到零時,您就知道所有線程都已完成。

在處理短期線程時需要小心,以確保允許計數器在遞減之前遞增。 需要使用某種鎖定或Interlocked.IncrementDecrement來修改計數器變量。 資源

您可以為活動線程數保留一個簡單的計數器。 或者,您可以讓線程在開始工作之前將自己注冊(添加)到集合中,並在完成后將其刪除。

計數工作,但可能比你想象的更難實現......確保在線程內的finally塊中進行遞減並同步( lock )對計數器的訪問(我知道,它應該是原子的,但無論如何...... .)。

如果您只創建一些線程並擁有線程實例,您也可以 Thread.Join 每個實例。 即使在您調用 join 之前線程已終止(但仍在清理實例之前),這仍然有效。

所以:

foreach( Thread thread in myThreads)
{
   thread.join();
}

一旦完成,您就確定所有線程都已完成。

hth

馬里奧

最簡單的方法是,如果您事先知道將要運行的線程數,則可以在回調 function 中使用計數器。

如果您不知道線程數,那么您需要一些“處理結束”指示器來設置 boolean 以及創建和結束線程的計數器。

如果您不知道將創建的線程數,那么簡單的兩個計數器的想法就行不通(如果第一個線程在創建任何其他線程之前開始和結束,它會錯誤地認為它是最后一個一)。

在 threader 線程中檢查每個線程的狀態。 如果所有線程都停止(或中止),你知道你可以結束主線程。

您可以使用WaitHandle s。 如果您使用 BeginInvoke/EndInvoke 來控制您的線程,這將變得更具吸引力(因為IAsyncResult帶有WaitHandle )。 請記住,在WaitAll調用期間不要超過 64 個項目的操作系統限制。 這是一種使過程更簡單的擴展方法:

static class ThreadingExtensions
{
    // Possible:
    // [ThreadStatic]
    // private static List<WaitHandle> PerThreadWaitList;
    public const int MaxHandlesPerWait = 64;

    public static void WaitAll<T>(this IEnumerable<T> handles, int millisecondsTimeout, int estimatedCount)
        where T : WaitHandle
    {
        // Possible:
        // var currentSet = PerThreadWaitList ?? (PerThreadWaitList = new List<WaitHandle>(estimatedCount));
        var currentSet = new List<WaitHandle>(Math.Min(estimatedCount, MaxHandlesPerWait));
        var timeoutEnd = Environment.TickCount + millisecondsTimeout;
        int timeout;

        // Wait for items in groups of 64.
        foreach (var item in handles)
        {
            currentSet.Add(item);
            if (currentSet.Count == MaxHandlesPerWait)
            {
                timeout = Timeout.Infinite;
                if (millisecondsTimeout >= 0)
                {
                    timeout = timeoutEnd - Environment.TickCount;
                    if (timeout < 0)
                        throw new TimeoutException();
                }
                WaitHandle.WaitAll(currentSet.ToArray(), timeout);
                currentSet.Clear();
            }
        }

        // Do the last set.
        if (currentSet.Count > 0)
        {
            timeout = Timeout.Infinite;
            if (millisecondsTimeout >= 0)
            {
                timeout = timeoutEnd - Environment.TickCount;
                if (timeout < 0)
                    timeout = 0;
            }
            WaitHandle.WaitAll(currentSet.ToArray(), timeout);
            currentSet.Clear();
        }
    }
}

以及一個使用示例。

var results = new List<IAsyncResult>();
// Call delegates, e.g.
// results.Add(Foo.BeginInvoke(OnEndInvokeFoo));
results.Select(x => x.AsyncWaitHandle).WaitAll(Timeout.Infinite, results.Count);

線程計數器的示例代碼

long counter = 0;

void ThreadEntryPoint()
{
  try
  {
    ...
    //
  }
  finally
  {
    // Decrement counter
    Interlocked.Decrement(ref counter);
  }
}

void MainThread()
{
  // Start worers
  for(...)
  {
    // Increment threads couter
    Interlocked.Increment(ref counter);
    ((Action)ThreadEntryPoint).BeginInvoke(null, null);
  }

  // Wait until counter is equal to 0
  while(Interlocked.Read(ref counter) != 0)
  {
    Thread.Sleep(0);
  }
}

暫無
暫無

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

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