【问题标题】:How to block new threads until all threads are created and started如何阻止新线程,直到创建并启动所有线程
【发布时间】:2013-08-08 07:45:39
【问题描述】:

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

我的代码包含这个循环:

        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);

【问题讨论】:

  • 您可以使用 TPL 并设置任务列表吗?除非你特别想以这种方式学习?
  • 在新的 .net 框架中,您有 async 关键字。单词检查以更新您的技能。
  • @lordkain 然而,与这种情况无关

标签: c# multithreading synchronization


【解决方案1】:

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

话虽如此,有一些同步对象可能会满足您的要求。我认为Barrier 类(Fx 4+)是你想要的。

【讨论】:

  • 这个小应用是我在网上找到的一个练习,它专门指导我为每匹马设置一个线程。代码可能会保持现在的状态,在我看来,如果一个线程在所有并行创建之前开始工作,则应用程序无法模拟实际的比赛。
  • 修复该问题后(使用 Barrier),您的应用仍将“无法模拟实际比赛”。但是对于锻炼来说没关系。
【解决方案2】:

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();
        }
    }
}

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

【讨论】:

    【解决方案3】:

    我会看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);
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-13
      • 1970-01-01
      • 2012-11-28
      相关资源
      最近更新 更多