C # Генератор случайных чисел застревает в цикле - PullRequest
5 голосов
/ 26 апреля 2010

Я использую .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 ]

11 голосов
/ 26 апреля 2010

Класс Random не является поточно-ориентированным.

Вы должны сделать свой static экземпляр [ThreadStatic] или защитить его с помощью замка.

3 голосов
/ 26 апреля 2010

Если вы используете только один RNG для нескольких потоков, даже если вы сохраните начальное число, вы не сможете сгенерировать те же номера при следующем запуске приложения, потому что вы не будете уверены, что вызовы к RNG из разных потоков будет в том же порядке.

Если у вас фиксированное / известное количество нитей, сделайте ГСЧ для каждой нитки и сохраните каждое семя.

Забудьте то, что я только что сказал, если вы на 100% уверены, что каждый поток будет вызывать ГСЧ с точно таким же порядком, как в прошлый раз, если вы используете то же начальное число.

1 голос
/ 26 апреля 2010

Мне даже не нужно искать класс Random, который знает "все методы экземпляра этого класса или не потокобезопасные". Это относится ко всем классам .NET, за очень немногими исключениями.

Так что да, это многопоточность. Но вы также не упомянули о проверке MaxValue> MinValue.

1 голос
/ 26 апреля 2010

Идея состоит в том, что если я буду использовать один и тот же генератор случайных чисел во всем приложении, я мог бы просто сохранить начальное значение и затем перезагрузить его, чтобы пересчитать определенный интересный прогон.

На самом деле для этого вам не нужен одноэлементный экземпляр ГСЧ. Если вы инициализируете два отдельных экземпляра Random для одного и того же seed, они будут производить абсолютно одинаковую последовательность.

Мой совет: спасите семя, но избавьтесь от синглтона.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...