C#随机数生成器陷入循环中。

5

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

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。如果我在这个点上设置断点并尝试创建一个double并将其设置为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个回答

11

Random类不是线程安全的。

你应该将你的static实例标记为[ThreadStatic],或者用锁来保护它。


+1 for [ThreadStatic] - 从未听说过这个。 - Jonathon Reinhart

3
如果你在多个线程中只使用一个随机数生成器,即使你保存了种子,下次启动应用程序时也无法生成相同的数字,因为你无法确定不同线程对随机数生成器的调用顺序是否相同。如果你有固定/已知数量的线程,请为每个线程创建一个随机数生成器并保存每个种子。如果你确信每个线程在使用相同种子时的调用顺序与上一次完全相同,则可以忽略我刚才说的话。

糟糕,我把这个帖子的回答窗口打开时间太长了,+1... 这正是我想说的! - Eamon Nerbonne
谢谢,你说得非常正确。我接受了您的评论作为答案,并给您一些更多的积分:P 另外,感谢您告诉我关于其他多线程问题的事情,我还没有完全想到! - Jean Azzopardi

1
这个想法是,如果我在整个应用程序中使用相同的随机数生成器,我只需要保存种子,然后从种子重新加载以重新计算某个有趣的运行。
实际上,你不需要一个RNG的单例实例。如果你将两个独立的Random实例初始化为相同的种子,它们将产生完全相同的序列。
我的建议是,保存种子,但摆脱单例。

1

我甚至不需要查找Random类就知道"该类的所有实例方法是否都不是线程安全的"。对于所有.NET类都是如此,只有非常少的例外。

所以,是多线程。但您还没有提到验证MaxValue > MinValue。


实际上,我确实检查了这个问题,但你说得对...问题在于线程安全。 - Jean Azzopardi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接