如何在创建并启动所有线程之前阻止新线程

本文关键字:线程 新线程 创建 启动 | 更新日期: 2023-09-27 18:26:53

我正在构建一个模拟赛马的小型应用程序,以便获得使用线程的一些基本技能。

我的代码包含以下循环:

        for (int i = 0; i < numberOfHorses; i++)
        {
            horsesThreads[i] = new Thread(horsesTypes[i].Race);
            horsesThreads[i].Start(100);
        }

为了保持比赛的公平性,我一直在寻找一种方法,让所有新创建的线程等待,直到其他新线程设置好,然后启动所有线程,开始运行它们的方法(请注意,我知道从技术上讲,线程不能同时启动)

所以基本上,我正在寻找这样的东西:

        for (int i = 0; i < numberOfHorses; i++)
        {
            horsesThreads[i] = new Thread(horsesTypes[i].Race);
        }
        Monitor.LaunchThreads(horsesThreads);

如何在创建并启动所有线程之前阻止新线程

线程不能保证公平性或确定性结果,因此它不是模拟比赛的好方法。

话虽如此,有些同步对象可能会按照您的要求执行操作。我认为Barrier类(Fx4+)就是你想要的。

Barrier类就是为了支持这一点而设计的。

这里有一个例子:

using System;
using System.Threading;
namespace Demo
{
    class Program
    {
        private void run()
        {
            int numberOfHorses = 12;
            // Use a barrier with a participant count that is one more than the
            // the number of threads. The extra one is for the main thread,
            // which is used to signal the start of the race.
            using (Barrier barrier = new Barrier(numberOfHorses + 1))
            {
                var horsesThreads = new Thread[numberOfHorses];
                for (int i = 0; i < numberOfHorses; i++)
                {
                    int horseNumber = i;
                    horsesThreads[i] = new Thread(() => runRace(horseNumber, barrier));
                    horsesThreads[i].Start();
                }
                Console.WriteLine("Press <RETURN> to start the race!");
                Console.ReadLine();
                // Signals the start of the race. None of the threads that called
                // SignalAndWait() will return from the call until *all* the 
                // participants have signalled the barrier.
                barrier.SignalAndWait();
                Console.WriteLine("Race started!");
                Console.ReadLine();
            }
        }
        private static void runRace(int horseNumber, Barrier barrier)
        {
            Console.WriteLine("Horse " + horseNumber + " is waiting to start.");
            barrier.SignalAndWait();
            Console.WriteLine("Horse " + horseNumber + " has started.");
        }
        private static void Main()
        {
            new Program().run();
        }
    }
}

[EDIT]我刚刚注意到Henk已经提到了Barrier,但我将把这个答案留在这里,因为它有一些示例代码。

我会把ManualResetEvent看作一个门Thread内,递减一个计数器;如果它仍然为非零,请在门上等待;否则,打开大门。基本上:

using System;    
using System.Threading;
class Program
{
    static void Main()
    {
        ManualResetEvent gate = new ManualResetEvent(false);
        int numberOfThreads = 10, pending = numberOfThreads;
        Thread[] threads = new Thread[numberOfThreads];
        ParameterizedThreadStart work = name =>
        {
            Console.WriteLine("{0} approaches the tape", name);
            if (Interlocked.Decrement(ref pending) == 0)
            {
                Console.WriteLine("And they're off!");
                gate.Set();
            }
            else gate.WaitOne();
            Race();
            Console.WriteLine("{0} crosses the line", name);
        };
        for (int i = 0; i < numberOfThreads; i++)
        {
            threads[i] = new Thread(work);
            threads[i].Start(i);
        }
        for (int i = 0; i < numberOfThreads; i++)
        {
            threads[i].Join();
        }
        Console.WriteLine("all done");
    }
    static readonly Random rand = new Random();
    static void Race()
    {
        int time;
        lock (rand)
        {
            time = rand.Next(500,1000);
        }
        Thread.Sleep(time);
    }
}