每个线程另一个随机数

本文关键字:随机数 另一个 线程 | 更新日期: 2023-09-27 18:03:01

我有一个简单的类来生成随机数:

public class Bar
{
    Random rnd = new Random();
    public int GenerateRandomNumber()
    {
        return rnd.Next(1, 100);
    }
}

然后我在第二类中使用它,在那里我创建两个线程。每个线程都使用bar类的函数写控制台自己的id和随机数。如下所示:

public class Foo
{
    Thread t1;
    Thread t2;
    Bar bar;
    public Foo(Bar bar)
    {
        t1 = new Thread(GetRandomNumber);
        t2 = new Thread(GetRandomNumber);
        this.bar = bar;
    }
    public void Start()
    {
        t1.Start();
        t2.Start();
    }
    private void GetRandomNumber()
    {   
        Console.WriteLine("Thread {0} {1}", Thread.CurrentThread.ManagedThreadId,bar.GenerateRandomNumber());
    }
} 

那么在main中我有:

static void Main(string[] args)
{
    Bar bar1 = new Bar();
    Bar bar2 = new Bar();
    Foo f1 = new Foo(bar1);
    Foo f2 = new Foo(bar2);
    f1.Start();
    f2.Start();
    Console.ReadLine();
}

在控制台中,我可以得到例如:

Thread 11 34
Thread 12 9
Thread 13 34
Thread 14 9

我的问题是我能做些什么来获得每个线程的另一个数字?

每个线程另一个随机数

您需要用所谓的seed初始化随机生成器,这对于不同的线程是不同的。最简单的方法是:

Random rnd = new Random(Thread.CurrentThread.ManagedThreadId);


在你发布的代码中,简单地修改一行是没有用的。
为了它的工作,你必须改变它的方式,使每个线程都有自己的Random实例。就像这样:

public class Foo
{
    Thread t1;
    Thread t2;     
    public Foo(Func<Bar> getBar)
    {
        t1 = new Thread(()=>GetRandomNumber(getBar()));
        t2 = new Thread(()=>GetRandomNumber(getBar()));
    }
    public void Start()
    {
        t1.Start();
        t2.Start();
    }
    private void GetRandomNumber(Bar bar)
    {   
        Console.WriteLine("Thread {0} {1}", Thread.CurrentThread.ManagedThreadId,bar.GenerateRandomNumber());
    }
}
static void Main(string[] args)
{
    Foo f1 = new Foo(()=>new Bar());
    Foo f2 = new Foo(()=>new Bar());
    f1.Start();
    f2.Start();
    Console.ReadLine();
}

调用Random rnd = new Random();时,将根据系统时钟初始化随机数生成器的种子。那个时钟的分辨率不是很好(我不记得频率了,但我相信它每秒不到100次)。因此,您的两个线程使用系统时钟同时在Random实例中创建,因此它们具有相同的种子。

Seed决定了它将生成的伪随机数序列。由于两个线程获得相同的种子,因此可以得到相同的序列。

最好的解决方案是只创建一个Random对象的实例并将其传递给您的线程(并可能保护对它的访问,因为我不确定它是否mt安全)。

另一种方法是提供一些其他的种子生成器而不是默认的,例如将系统时间与线程id或类似的网格相结合(注意,仅将托管线程id作为种子可能不够,因为托管线程id通常倾向于挂在较低的范围内,因此您的随机种子将非常可预测,因此根本不是随机的)。