Генератор случайных чисел, возвращающий нули - PullRequest
2 голосов
/ 20 сентября 2010

У меня есть приложение ASP.NET, которое использует класс Random для генерации псевдослучайной строки.Он использует следующий код (это часть более крупного примера кода, предоставленного Google для единого входа приложений):

    public static class SamlUtility
{
    private static Random random = new Random();

    private static char[] charMapping =  { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p' };

    public static string CreateId()
    {
        byte[] bytes = new byte[20]; // 160 bits

        random.NextBytes(bytes);

        char[] chars = new char[40];

        for (int i = 0; i < bytes.Length; i++)
        {
            int left = (bytes[i] >> 4) & 0x0f;
            int right = bytes[i] & 0x0f;
            chars[i * 2] = charMapping[left];
            chars[i * 2 + 1] = charMapping[right];
        }

        return new string(chars);
    }
}

Обычно это работает очень хорошо, но время от времени он начинает генерировать строку«а».Из того, что я могу сказать из отладки, Random просто прекращает возвращать случайные числа и вместо этого заполняет байты одним и тем же значением снова и снова.Я исправил это, используя вместо этого GUID, но мне любопытно, что произошло в оригинальном коде.Я предполагаю некоторую форму истощения энтропии, но я не могу найти никаких ссылок в документах.Кроме того, каждый раз, когда это происходило, выполнение iisreset восстанавливало правильное поведение.

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

1 Ответ

6 голосов
/ 20 сентября 2010

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

Необходимо создать экземпляр Random [ThreadStatic], чтобы гарантировать, что каждый экземпляр не используется несколькими потоками.
Обратите внимание, что инициализаторы для полей [ThreadStatic] будут запускаться только один раз, поэтому вам нужно проверять, является ли оно null при каждом использовании поля, и инициализировать его при необходимости.
Также было бы неплохо включить в начальное число как идентификатор потока, так и текущее время, чтобы предотвратить столкновения начального числа.

Кстати, обратите внимание, что класс Random небезопасен; рассмотрите возможность использования RNGCryptoServiceProvider класса

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