C#随机数生成器卡在一个循环中

时间:2010-04-26 13:27:09

标签: c# thread-safety random

我正在使用.NET创建一个人工生命程序,我正在使用C#在Singleton中定义的伪随机类。我的想法是,如果我在整个应用程序中使用相同的随机数生成器,我只能保存种子,然后从种子重新加载以重新计算某个有趣的运行。

public sealed class RandomNumberGenerator : Random
{
    private static readonly RandomNumberGenerator instance = new RandomNumberGenerator();

    RandomNumberGenerator()
    {

    }

    public static RandomNumberGenerator Instance
    {
        get
        {
            return instance;
        }
    }
}

我还想要一种可以给我两个不同随机数的方法。

public static Tuple<int, int> TwoDifferentRandomNumbers(this Random rnd, int minValue, int maxValue)
    {
        if (minValue >= maxValue)
            throw new ArgumentOutOfRangeException("maxValue", "maxValue must be greater than minValue");
        if (minValue + 1 == maxValue)
            return Tuple.Create<int, int>(minValue, maxValue);

        int rnd1 = rnd.Next(minValue, maxValue);
        int rnd2 = rnd.Next(minValue, maxValue);
        while (rnd1 == rnd2)
        {                
            rnd2 = rnd.Next(minValue, maxValue);
        }
        return Tuple.Create<int, int>(rnd1, rnd2);            
    }

问题是有时候rnd.Next(minValue,maxValue总会返回minValue。如果此时断点并尝试创建双精度并将其设置为rnd.NextDouble(),则返回0.0。任何人都知道为什么会这样吗?

我知道它是一个伪随机数生成器,但坦率地说,我没想到它会锁定为0.从多个线程访问随机数生成器......这可能是问题的根源吗?

编辑:谢谢,问题最终是线程安全。

这是该课程的新版本。

 public sealed class RandomNumberGenerator : Random
{
    private static Random _global = new Random();
    [ThreadStatic]
    private static Random _localInstance;

    RandomNumberGenerator()
    {

    }

    public static Random Instance
    {
        get
        {
            Random inst = _localInstance;
            if (inst == null)
            {
                int seed;
                lock (_global) seed = _global.Next();
                _localInstance = inst = new Random(seed);
            }
            return _localInstance;
        }
    }
}

4 个答案:

答案 0 :(得分:11)

Random类不是线程安全的。

您应该制作static实例[ThreadStatic],或使用锁定保护它。

答案 1 :(得分:3)

如果即使保存种子也只使用一个RNG用于多个线程,则下次启动应用程序时将无法生成相同的数字,因为您无法确定对RNG的调用来自不同的线程将以相同的顺序。

如果您有一个固定/已知的线程数,则每个线程生成一个RNG并保存每个种子。

如果您100%确定每个线程将使用与上次使用相同种子时完全相同的顺序调用RNG,请忘记我刚刚说过的内容。

答案 2 :(得分:1)

  

我的想法是,如果我在整个应用程序中使用相同的随机数生成器,我只能保存种子,然后从种子重新加载以重新计算某个有趣的运行。

为此,您实际上不需要RNG的单例实例。如果您将Random的两个单独实例初始化为相同的seed,则它们将生成完全相同的序列。

我的建议是,保存种子,但摆脱单身。

答案 3 :(得分:1)

我甚至不必查看Random类,知道“此类的所有实例方法或不是线程安全的”。这适用于所有.NET类,只有极少数例外。

是的,它是多线程的。但你没有提到验证MaxValue&gt; MinValue也是。