簡體   English   中英

等到所有線程在 ThreadPool 中完成工作

[英]Wait until all threads finished their work in ThreadPool

我有這個代碼:

var list = new List<int>();
for(int i=0;i<10;i++) list.Add(i); 
for(int i=0;i<10;i++)
{
     ThreadPool.QueueUserWorkItem(
         new WaitCallback(x => {
             Console.WriteLine(x);  
         }), list[i]);
} 

我想知道所有線程池線程何時完成工作。 我怎么能做到這一點?

你需要自己跟蹤這個。

一種選擇是使用計數器和重置事件:

int toProcess = 10;
using(ManualResetEvent resetEvent = new ManualResetEvent(false))
{
    var list = new List<int>();
    for(int i=0;i<10;i++) list.Add(i); 
    for(int i=0;i<10;i++)
    {
        ThreadPool.QueueUserWorkItem(
           new WaitCallback(x => {
              Console.WriteLine(x);  
              // Safely decrement the counter
              if (Interlocked.Decrement(ref toProcess)==0)
                 resetEvent.Set();

           }),list[i]);
    } 

    resetEvent.WaitOne();
}
// When the code reaches here, the 10 threads will be done
Console.WriteLine("Done");

在 .NET Framework 4+ 中使用方便的 System.Threading.CountdownEvent 類:

const int threadCount = 10;
var list = new List<int>(threadCount);
for (var i = 0; i < threadCount; i++) list.Add(i);

using (var countdownEvent = new CountdownEvent(threadCount))
{
    for (var i = 0; i < threadCount; i++)
        ThreadPool.QueueUserWorkItem(
            x =>
            {
                Console.WriteLine(x);
                countdownEvent.Signal();
            }, list[i]);

    countdownEvent.Wait();
}
Console.WriteLine("done");

我不確定 ThreadPool 是否公開了這樣的功能,但您可以使用等待句柄,順便說一下,迭代兩次似乎沒有必要:

var events = new ManualResetEvent[10];
var list = new List<int>();
for (int i = 0; i < 10; i++)
{
    list.Add(i);
    events[i] = new ManualResetEvent(false);
    int j = i;
    ThreadPool.QueueUserWorkItem(x => {
        Console.WriteLine(x);
        events[j].Set();
    }, list[i]);
}
WaitHandle.WaitAll(events);

這就是我要做的。

class Program
{
    static void Main(string[] args)
    {
        var items = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        using (var countdown = new Countdown(items.Length))
        {
            foreach (var item in items)
            {
                ThreadPool.QueueUserWorkItem(o =>
                {
                    Thread.SpinWait(100000000);
                    Console.WriteLine("Thread Done!");
                    countdown.Signal();
                });
            }
            countdown.Wait();
        }
        Console.WriteLine("Job Done!");
        Console.ReadKey();
    }

    public class Countdown : IDisposable
    {
        private readonly ManualResetEvent done;
        private readonly int total;
        private volatile int current;

        public Countdown(int total)
        {
            this.total = total;
            current = total;
            done = new ManualResetEvent(false);
        }

        public void Signal()
        {
            lock (done)
            {
                if (current > 0 && --current == 0)
                    done.Set();
            }
        }

        public void Wait()
        {
            done.WaitOne();
        }

        public void Dispose()
        {
            done.Dispose();
        }
    }
} 

線程池不會告訴您線程何時完成執行,因此工作項必須自己完成。 我改變了這樣的代碼:

    var list = new List<int>();
    ManualResetEvent[] handles = new ManualResetEvent[10];
    for (int i = 0; i < 10; i++) {
        list.Add(i);
        handles[i] = new ManualResetEvent(false);
    }
    for (int i = 0; i < 10; i++) {
        ThreadPool.QueueUserWorkItem(
         new WaitCallback(x =>
         {
             Console.WriteLine(x);
             handles[(int) x].Set();
         }), list[i]);
    }

    WaitHandle.WaitAll(handles);
    static void Main(string[] args)
    {
        for (int i = 0; i < 10; i++)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(xyz));
        }

        bool working = true;
        ThreadPool.GetMaxThreads(out int maxWorkerThreads, out int maxCompletionPortThreads);
        while (working)
        {
            ThreadPool.GetAvailableThreads(out int workerThreads, out int completionPortThreads);
            //Console.WriteLine($"{workerThreads} , {maxWorkerThreads}");
            if (workerThreads == maxWorkerThreads)
            { working = false; }
        }
        //when all threads are completed then 'working' will be false 
    }
    void xyz(object o)
    {
        console.writeline("");
    }

暫無
暫無

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

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