C# 多线程的等待所有线程结束的一个问题

时间:2021-11-06 18:28:23
请问各位一个问题 我有一个带参数的方法需要多线程执行,如何等待线程都执行完了再执行主线程的代码呢?

如下是我写的代码,但是没法调用events.Set(),如有更好的建议也行
不希望使用线程池,因为我以后考虑提供暂停线程的方法

   class Program
    {
        private static AutoResetEvent[] events;
        static void Main(string[] args)
        {
            int threadNum = 10;
            Thread[] thread = new Thread[threadNum];

            events = new AutoResetEvent[threadNum];

            for (int i = 0; i < threadNum; i++)
            {
                events[i] = new AutoResetEvent(false);

                ThreadStart starter = delegate
                                          {
                                              Print("test print:" + i);
                                          };
                thread[i] = new Thread(starter)
                                {
                                    Name = "thread" + i.ToString()
                                };
            }

            for (int i = 0; i < threadNum; i++)
            {
                thread[i].Start();
            }

            WaitHandle.WaitAll(events);
            Console.Read();
        }

        private static void Print(object str)
        {
            Console.WriteLine(Thread.CurrentThread.Name + ": Begin!");
            Console.WriteLine(Thread.CurrentThread.Name + ": Print" + str);
            Console.WriteLine(Thread.CurrentThread.Name + ": End!");

            //events[eventNum].Set();
        }
    }

6 个解决方案

#1


using System;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        private static AutoResetEvent[] events;

        static void Main(string[] args)
        {
            int threadNum = 10;
            Thread[] thread = new Thread[threadNum];

            events = new AutoResetEvent[threadNum];

            for (int i = 0; i < threadNum; i++)
            {
                var waithandler = new AutoResetEvent(false);
                events[i] = waithandler;
                ThreadStart starter = delegate
                {
                    var param = new Tuple<string, AutoResetEvent>("test print:" + i, waithandler);
                    Print(param);
                };
                thread[i] = new Thread(starter)
                {
                    Name = "thread" + i.ToString()
                };
            }

            for (int i = 0; i < threadNum; i++)
            {
                thread[i].Start();
            }

            WaitHandle.WaitAll(events);
            Console.WriteLine("Completed!");
            Console.Read();

        }

        private static void Print(object param)
        {
            var p = (Tuple<string, AutoResetEvent>)param;
            Console.WriteLine(Thread.CurrentThread.Name + ": Begin!");
            Console.WriteLine(Thread.CurrentThread.Name + ": Print" + p.Item1);
            Thread.Sleep(300);
            Console.WriteLine(Thread.CurrentThread.Name + ": End!");
            p.Item2.Set();
        }
    }
}

#2


既然是一次性地Set,其实使用ManualResetEvent就足够了。

另外,“暂停”线程跟线程池也没有什么直接冲突。不论你使用还是不使用系统线程池,所谓的“暂停”线程都一样地影响系统。只不过是让线程池中少一个可用线程(而.net4.0线程池中默认可以有2000多工作线程+I/O线程)。

#3


改了一下,使用ManualResetEvent:
using System;
using System.Collections.Generic;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var waits = new List<EventWaitHandle>();
            for (int i = 0; i < 10; i++)
            {
                var handler = new ManualResetEvent(false);
                waits.Add(handler);
                new Thread(new ParameterizedThreadStart(Print))
                {
                    Name = "thread" + i.ToString()
                }.Start(new Tuple<string, EventWaitHandle>("test print:" + i, handler));
            }
            WaitHandle.WaitAll(waits.ToArray());
            Console.WriteLine("Completed!");
            Console.Read();

        }

        private static void Print(object param)
        {
            var p = (Tuple<string, EventWaitHandle>)param;
            Console.WriteLine(Thread.CurrentThread.Name + ": Begin!");
            Console.WriteLine(Thread.CurrentThread.Name + ": Print" + p.Item1);
            Thread.Sleep(300);
            Console.WriteLine(Thread.CurrentThread.Name + ": End!");
            p.Item2.Set();
        }

    }
}

#4


非常感谢你的回答,麻烦再请教下,用线程池如何暂停一个指定的线程呢?

#5


该回复于2011-10-17 13:25:40被版主删除

#6


thanks for you message

#1


using System;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        private static AutoResetEvent[] events;

        static void Main(string[] args)
        {
            int threadNum = 10;
            Thread[] thread = new Thread[threadNum];

            events = new AutoResetEvent[threadNum];

            for (int i = 0; i < threadNum; i++)
            {
                var waithandler = new AutoResetEvent(false);
                events[i] = waithandler;
                ThreadStart starter = delegate
                {
                    var param = new Tuple<string, AutoResetEvent>("test print:" + i, waithandler);
                    Print(param);
                };
                thread[i] = new Thread(starter)
                {
                    Name = "thread" + i.ToString()
                };
            }

            for (int i = 0; i < threadNum; i++)
            {
                thread[i].Start();
            }

            WaitHandle.WaitAll(events);
            Console.WriteLine("Completed!");
            Console.Read();

        }

        private static void Print(object param)
        {
            var p = (Tuple<string, AutoResetEvent>)param;
            Console.WriteLine(Thread.CurrentThread.Name + ": Begin!");
            Console.WriteLine(Thread.CurrentThread.Name + ": Print" + p.Item1);
            Thread.Sleep(300);
            Console.WriteLine(Thread.CurrentThread.Name + ": End!");
            p.Item2.Set();
        }
    }
}

#2


既然是一次性地Set,其实使用ManualResetEvent就足够了。

另外,“暂停”线程跟线程池也没有什么直接冲突。不论你使用还是不使用系统线程池,所谓的“暂停”线程都一样地影响系统。只不过是让线程池中少一个可用线程(而.net4.0线程池中默认可以有2000多工作线程+I/O线程)。

#3


改了一下,使用ManualResetEvent:
using System;
using System.Collections.Generic;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var waits = new List<EventWaitHandle>();
            for (int i = 0; i < 10; i++)
            {
                var handler = new ManualResetEvent(false);
                waits.Add(handler);
                new Thread(new ParameterizedThreadStart(Print))
                {
                    Name = "thread" + i.ToString()
                }.Start(new Tuple<string, EventWaitHandle>("test print:" + i, handler));
            }
            WaitHandle.WaitAll(waits.ToArray());
            Console.WriteLine("Completed!");
            Console.Read();

        }

        private static void Print(object param)
        {
            var p = (Tuple<string, EventWaitHandle>)param;
            Console.WriteLine(Thread.CurrentThread.Name + ": Begin!");
            Console.WriteLine(Thread.CurrentThread.Name + ": Print" + p.Item1);
            Thread.Sleep(300);
            Console.WriteLine(Thread.CurrentThread.Name + ": End!");
            p.Item2.Set();
        }

    }
}

#4


非常感谢你的回答,麻烦再请教下,用线程池如何暂停一个指定的线程呢?

#5


该回复于2011-10-17 13:25:40被版主删除

#6


thanks for you message