C#enque随机整数

C#enque随机整数,c#,multithreading,random,int,queue,C#,Multithreading,Random,Int,Queue,我有三个线程,它们应该向队列中添加一个随机整数,第四个线程将整数排出来,第五个线程打印其中的数字。我之所以使用线程,是因为在这个程序的作用域中,它们最终会被需要,并且会对更多的数字进行排队/出列,但是在生成随机整数时会遇到问题。我使用一个类RandomGenerator来创建数字,并创建这个类的一个实例,然后调用它的GetRandom方法将一个int字段设置为随机数。然后我将这个字段传递给前三个线程,它们调用该方法来排队。打印的int不是随机的,我意识到这是因为我只是在程序开始时调用该方法,并将

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

类程序
{
静态void Main()
{
程序p=新程序();
RandomGenerator rg=新的RandomGenerator();
Queue numberQueue=新队列();
int randomNumber=rg.GetRandom(1,10);
线程T1=新线程(委托(){p.EnqueueNumber(numberQueue,randomNumber);});
线程T2=新线程(委托(){p.EnqueueNumber(numberQueue,randomNumber);});
线程T3=新线程(委托(){p.EnqueueNumber(numberQueue,randomNumber);});
线程T4=新线程(委托(){p.DequeueNumber(numberQueue);});
线程T5=新线程(委托(){p.PrintNumbers(numberQueue);});
T1.Start();
T2.Start();
T3.Start();
T4.开始();
T5.开始();
T1.Join();
T2.连接();
T3.Join();
T4.Join();
T5.连接();
}
公共无效排队编号(队列编号Queue,int randomNumber)
{
numberQueue.Enqueue(随机数);
}
公共无效出列编号(队列编号Queue)
{
numberQueue.Dequeue();
}
公共无效打印编号(队列编号队列)
{
foreach(数字队列中的int i)
{
控制台。写入(i);
}
Console.ReadKey();
}
}
公共类随机发生器
{
私有静态随机_Random=新随机();
私有静态对象syncLock=新对象();
公共整数GetRandom(整数最小值,整数最大值)
{
锁定(同步锁定)
{
返回_random.Next(最小值、最大值);
}
}
}

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

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

Thread T1 = new Thread(delegate () { p.EnqueueNumber(numberQueue, rg); });
如果您为每个线程创建了一个
RandomGenerator
,那么您也可以停止使用锁,这种锁对于这个用例来说是多余的


最后,如果您坚持对同一队列执行并发多写、单读操作,您还应该查看而不是队列,因为它是线程安全的。

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

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

Thread T1 = new Thread(delegate () { p.EnqueueNumber(numberQueue, rg); });
如果您为每个线程创建了一个
RandomGenerator
,那么您也可以停止使用锁,这种锁对于这个用例来说是多余的


最后,如果您坚持对同一队列执行并发多写、单读操作,您还应该考虑而不是队列,因为它是线程安全的。

注意线程安全。
队列
类不是线程安全的。还要注意,您尝试实现的模式被称为“生产者-消费者”模式,并且.NET平台包含用于轻松、稳健地实现此模式的专用工具。你可以看一看这个类,它不是最好的,但它是最容易学习的。我会考虑查看<代码> [线程静态]私有静态随机变量=新的随机变量()。code>因为这将消除获取随机数时
锁定
的需要。@Enigmativity是的,但代价是每个线程创建一个
随机
实例。也许没什么大不了的,但要知道这一点很重要。注意线程安全。
队列
类不是线程安全的。还要注意,您尝试实现的模式被称为“生产者-消费者”模式,并且.NET平台包含用于轻松、稳健地实现此模式的专用工具。你可以看一看这个类,它不是最好的,但它是最容易学习的。我会考虑查看<代码> [线程静态]私有静态随机变量=新的随机变量()。code>因为这将消除获取随机数时
锁定
的需要。@Enigmativity是的,但代价是每个线程创建一个
随机
实例。也许没什么大不了的,但要知道这一点很重要。注意每个线程使用一个随机数生成器。如果它们都在同一毫秒内初始化,它们很可能各自生成相同的随机数序列。默认构造函数从系统时间(以毫秒为单位)获取种子。另外,我建议您不要使用
ConcurrentQueue
。它有一个更友好的界面。默认情况下,它由一个
ConcurrentQueue
支持,因此行为是相同的。请注意每个线程使用一个随机数生成器。如果它们都在同一毫秒内初始化,它们很可能各自生成相同的随机数序列。国防部