簡體   English   中英

如何讓等待所有線程完成它在c#中的線程池中工作

[英]how to make Wait until all threads finished it's work from threadpool in c#

for (int task = 0; task < 20; task++)
{

    ThreadPool.QueueUserWorkItem(new WaitCallback(TaskCallBack), new object[] { filepath1, filepath2, 
                  filepath3 });

}

public static void TaskCallBack(object state)
{
            object[] array = state as object[];
            string filea = Convert.ToString(array[0]);
            string fileb = Convert.ToString(array[1]);
            string filec = Convert.ToString(array[2]);
            //something below         

}

我希望主線程等待所有線程完成其工作。 請幫忙

處理此問題的最佳方法是使用Task.Run()Task.WhenAll() ,或使用Parallel.Invoke()

但是,如果您需要使用ThreadPool.QueueUserWorkItem您可以按如下方式解決此問題:

  1. 為了便於使用,將所有要傳遞給線程的數據封裝在一個類中。 此數據應包括一個CountdownEvent實例,該實例初始化的計數等於您要等待的線程數。 (在下面的示例代碼中,此類稱為ThreadData 。)
  2. TaskCallBack()方法中,當方法完成時調用CountdownEvent.Signal()
  3. 在主線程內部,啟動所有線程池線程,然后調用CountdownEvent.Wait()等待所有線程完成。

將所有這些放在一個可編譯的控制台應用程序中:

using System;
using System.Threading;

namespace CoreConsole
{
    public sealed class ThreadData
    {
        public ThreadData(CountdownEvent countdown, int index)
        {
            Countdown = countdown;
            Index     = index;
        }

        public CountdownEvent Countdown { get; }
        public int Index { get; }
    }

    public static class Program
    {
        static void Main()
        {
            int n = 20;
            var countdown  = new CountdownEvent(n);

            for (int task = 0; task < n; task++)
            {
                ThreadPool.QueueUserWorkItem(TaskCallBack, new ThreadData(countdown, task));
            }

            Console.WriteLine("Waiting for all threads to exit");

            countdown.Wait();

            Console.WriteLine("Waited for all threads to exit");
        }

        public static void TaskCallBack(object state)
        {
            var data = (ThreadData) state;

            Console.WriteLine($"Thread {data.Index} is starting.");

            Thread.Sleep(_rng.Next(2000, 10000));
            data.Countdown.Signal();

            Console.WriteLine($"Thread {data.Index} has finished.");
        }

        static readonly Random _rng = new Random(45698);
    }
}

ThreadData.Index屬性僅用於標識Console.WriteLine()調用中的每個線程。

注意:在實際代碼中,即使線程拋出異常,始終發出Countdown事件信號很重要 - 因此您應該將代碼包裝在 try/finally 中,如下所示:

public static void TaskCallBack(object state)
{
    var data = (ThreadData)state;

    try
    {
        // Do work here.
        Console.WriteLine($"Thread {data.Index} is starting.");
        Thread.Sleep(_rng.Next(2000, 10000));
        Console.WriteLine($"Thread {data.Index} has finished.");
    }

    finally
    {
        data.Countdown.Signal();
    }
}

就像@Ackdari 在他的評論中提到的那樣,您可以使用Task.Run 但是您不需要await關鍵字。 只需使用任務創建一個集合並等待它。

例子:

// Create a list that will hold the tasks
List<Task> tasks = new List<Task>;

// Create the tasks
for (int taskId = 0; taskId < 20; task++)
{
  tasks.Add(Task.Run(() => { TaskCallBack(new object[] { filepath1, filepath2, filepath3 }); }));
}

// Wait for ALL tasks to complete
Task.WaitAll(tasks.ToArray());

這樣你也可以使用你自己的方法來運行任務。 例子:

public static void ReplaceWithABetterName(string[] filePaths)
{
   string filea = filePaths[0);
   string fileb = filePaths[1];
   string filec = filePaths[2];
   //do stuff       
}

暫無
暫無

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

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