【问题标题】:C# enque random intC# enque 随机整数
【发布时间】:2020-07-16 04:22:54
【问题描述】:

我有三个线程应该将一个随机 int 添加到队列中,第四个线程将 int 出队,第五个线程打印其中的数字。我正在使用线程,因为在该程序的范围内最终将需要它们并将更多的数字入队/出队,但是在生成随机整数时会遇到问题。我正在使用 RandomGenerator 类来创建数字,并创建此类的实例,然后调用其 GetRandom 方法将 int 字段设置为随机数。然后,我将此字段传递给前三个线程,这些线程调用该方法进行排队。打印的 int 不是随机的,我意识到这是因为我只是在程序开始时调用该方法并将相同的确切数字传递给所有三个线程。我对 C# 比较陌生,并意识到我可能犯了一个基本错误。我还意识到第四个线程有时会在队列为空时访问队列,但目前并不那么重要。我已经尝试了许多不同的方法,并且还可以在 Program 类中使用数字生成器。代码如下:

...

class Program
{
    static void Main()
    {
        Program p = new Program();
        RandomGenerator rg = new RandomGenerator();

        Queue<int> numberQueue = new Queue<int>();

        int randomNumber = rg.GetRandom(1, 10);

        Thread T1 = new Thread(delegate () { p.EnqueueNumber(numberQueue, randomNumber); });
        Thread T2 = new Thread(delegate () { p.EnqueueNumber(numberQueue, randomNumber); });
        Thread T3 = new Thread(delegate () { p.EnqueueNumber(numberQueue, randomNumber); });
        Thread T4 = new Thread(delegate () { p.DequeueNumber(numberQueue); });
        Thread T5 = new Thread(delegate () { p.PrintNumbers(numberQueue); });

        T1.Start();
        T2.Start();
        T3.Start();
        T4.Start();
        T5.Start();

        T1.Join();
        T2.Join();
        T3.Join();
        T4.Join();
        T5.Join();
    }

    public void EnqueueNumber(Queue<int> numberQueue, int randomNumber)
    {
        numberQueue.Enqueue(randomNumber);
    }

    public void DequeueNumber(Queue<int> numberQueue)
    {
        numberQueue.Dequeue();
    }

    public void PrintNumbers(Queue<int> numberQueue)
    {
        foreach (int i in numberQueue)
        {
            Console.Write(i);
        }

        Console.ReadKey();
    }
}

public class RandomGenerator
{
    private static Random _random = new Random();
    private static object syncLock = new object();

    public int GetRandom(int min, int max)
    {
        lock (syncLock)
        {
            return _random.Next(min, max);
        }
    }
}

...

【问题讨论】:

  • 小心线程安全。 Queue 类不是线程安全的。另请注意,您尝试实现的模式称为“生产者-消费者”模式,并且 .NET 平台包含用于轻松且稳健地实现此模式的专用工具。你可以看看BlockingCollection 类的例子,它不是最好的,但它是最容易学习的。
  • 我会考虑查看[ThreadStatic] private static Random _random = new Random();,因为这样在获取随机数时就不需要lock
  • @Enigmativity 是的,但代价是为每个线程创建一个 Random 实例。也许没什么大不了的,但重要的是要知道。

标签: c# multithreading random int queue


【解决方案1】:

您正在将单个 RandomGenerator 实例的 GetRandom() 方法的返回 传递给每个线程。

您需要将RandomGenerator引用 传递给每个线程,以便每次都可以调用GetRandom()

Thread T1 = new Thread(delegate () { p.EnqueueNumber(numberQueue, rg); });

如果你为每个线程创建一个RandomGenerator,你也可以停止使用对于这个用例来说太过分的锁。

最后,如果你坚持从同一个队列并发多写单读,你还应该看看ConcurrentQueue而不是队列,因为它是线程安全的。

【讨论】:

  • 注意每个线程只有一个随机数生成器。如果它们都在同一毫秒内初始化,它们很可能各自生成相同的随机数序列。默认构造函数从系统时间获取种子,以毫秒为单位报告。另外,我建议使用BlockingCollection,而不是ConcurrentQueue。它有一个更友好的界面。默认情况下,它由ConcurrentQueue 支持,因此行为是相同的。
猜你喜欢
  • 2010-11-25
  • 1970-01-01
  • 2011-06-26
  • 2018-11-06
  • 2015-09-07
  • 1970-01-01
  • 2011-12-08
  • 1970-01-01
  • 2015-01-27
相关资源
最近更新 更多