【问题标题】:C# Random Number Generator getting stuck in a cycleC# 随机数生成器陷入循环
【发布时间】:2011-02-12 09:56:24
【问题描述】:

我正在使用 .NET 创建一个人工生命程序,并且我正在使用在 Singleton 中定义的 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。如果我此时断点并尝试创建一个双精度并将其设置为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;
        }
    }
}

【问题讨论】:

    标签: c# thread-safety random


    【解决方案1】:

    Random 类不是线程安全的。

    你应该让你的static实例[ThreadStatic],或者用锁保护它。

    【讨论】:

    【解决方案2】:

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

    如果您有固定/已知数量的线程,请为每个线程创建一个 RNG 并保存每个种子。

    如果你 100% 确定如果你使用相同的种子,每个线程都会以与上次完全相同的顺序调用 RNG,那么忘记我刚才所说的话。

    【讨论】:

    • 哎呀,我让这个帖子回答窗口打开的时间太长了,+1...这正是我想说的!
    • 谢谢,您说的完全正确。我接受了您的评论作为答案,给您更多的业力:P 另外,感谢您告诉我其他多线程问题,我并没有完全想到它!
    【解决方案3】:

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

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

    我的建议是,保留种子,但摆脱单例。

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

      • 实际上,我确实检查过,但你是对的......问题是线程安全。
      猜你喜欢
      • 2013-01-18
      • 1970-01-01
      • 2017-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-02
      • 2014-02-14
      • 1970-01-01
      相关资源
      最近更新 更多