类的一个实例上的线程池,如何等到所有线程完成

本文关键字:线程 一个 实例 | 更新日期: 2023-09-27 18:35:17

请考虑下面的代码。我不想创建多个class Waiter实例。(所以我不能使用手动重置事件类)

using System;
using System.Threading;
    public class Waiter
    {
        static int counter=0;
        static int max=20;
        public void Start()
        {
            for (int i = 1; i <= max; i++)
            {
                ThreadPool.QueueUserWorkItem(DoWork, (object)i);
            }
            Console.Read();//without this line the application quits before all threads are complete :(
        }
        public void DoWork(object o)
        {
            try
            {
                Thread.Sleep(1000);
            }
            finally
            {
                counter++;
                Console.WriteLine(counter);
                if (counter==max )
                {
                    Console.WriteLine("All threads complete");
                }
            }

        }
    }
    public class ThreadPoolExample
    {
        static void Main()
        {
            Waiter wtr=new Waiter();
            wtr.Start();

        }
    }

我对上面的代码有两个问题

1>如果没有Console.Read(),应用程序将在所有线程结束之前退出。

2>语句Console.WriteLine("All threads complete");执行两次。

我该如何解决这个问题?

类的一个实例上的线程池,如何等到所有线程完成

改用 Tasks,然后你可以执行 Task.WaitAll(tasks);

此外,通过工厂实例化您的任务:

Task.Factory.StartNew(() => { Console.Writeline(""); });

它将为您使用线程池。

您应该使用 Interlocked.Increment 来递增counter 。 因为当两个线程尝试同时递增它时,存在争用条件。

如果要同时使用多个Writer实例,则不能使用静态counter变量。 他们会互相争斗。 只需将其设置为私有实例变量,您应该没问题。 如果 Max 从未更改,则应constreadonly(并保持静态),或者如果可以更改,它也应该是一个实例字段。

最后,如果你有一个非静态ManualResetEvent实例,你可以在Start中创建它,初始化它以设置,在循环结束时等待它,然后在最后一个线程完成时发出信号(你目前只是写入控制台)。