Как генерировать разные случайные числа для разных потоков в .NET? - PullRequest
1 голос
/ 28 марта 2010

Я должен генерировать 19-битные случайные числа. Однако есть ограничение - два потока могут не генерировать одно и то же случайное число при выполнении определенного кода.

Самое простое решение - заблокировать весь код. Тем не менее, я хотел бы знать, есть ли неблокирующее решение. Я думал, что могу включить ManagedThreadId в производимые случайные числа, но в документации ManagedThreadId в Интернете упоминается, что он может охватывать весь диапазон Int32. Кажется, неуправляемый идентификатор потока ограничен 11 битами, но у меня остается только 8 действительно случайных битов.

Есть ли другие способы? Как-то использовать Thread Local Storage, может быть?

Спасибо.

EDIT

Я хочу кое-что прояснить. Случайные числа могут повторяться, это неизбежно, в конце концов. Чего я хочу избежать, так это если один кусок кода одновременно вводится двумя потоками, тогда эти потоки могут не использовать одно и то же случайное число, гарантировано. До или после выполнения этого кода - хорошо, но не в самом коде. Опять же, я могу использовать некоторую схему блокировки, чтобы предотвратить ее, но сначала я хочу изучить схемы без блокировки.

РЕДАКТИРОВАТЬ 2

Читая комментарии / ответы на мой вопрос, я понял, что не могу избежать, кроме как заблокировать конкретный код. Однако ради чисто академического любопытства мне все еще интересно знать, знает ли кто-нибудь хорошее решение моего первоначального вопроса - генерировать 19-битные случайные числа в нескольких потоках, где числа гарантированно различаются между потоками, учитывая, что ManagedThreadId может быть потенциально очень большим, настолько большим, что простое объединение его в случайное число является плохим - не оставляет места для реальных случайных битов.

Ответы [ 3 ]

2 голосов
/ 28 марта 2010

Используйте локальное хранилище потока для хранения ссылки на объект System::Random. Присвойте каждому потоку свою собственную ГСЧ (вы можете достаточно легко сказать, если вы еще не распределили ее), и вы можете весело извлекать значения из каждого из них столько, сколько захотите. Вероятно, хорошей идеей будет обернуть код, чтобы получить в методе случайное число, специфичное для потока, так что вам нужно получить его правильно только один раз.


[Редактировать: Включить пример]

class example {
    [ThreadStatic]
    static Random threadLocalRandom;
    private int GimmeARandomNumber(int upperBound) {
        Random r = threadLocalRandom;
        if (r == null) {
            r = threadLocalRandom = new Random();
        }
        return r.Next(0, upperBound);
    }
}
2 голосов
/ 28 марта 2010

Ну, сколько потоков вы собираетесь использовать? Это ограничивающий фактор. Если вам нужно (скажем) 8 потоков, вы можете просто потерять 3 бита информации. Вы можете создать «фабрику генераторов», которая знает, сколько генераторов разрешено создать , и выдает исключение, если вы пытаетесь создать слишком много.

Ваше требование для отдельных номеров не очень ясно, хотя - даже если вы убедитесь, что один поток никогда не создаст тот же номер, который создал другой поток, вам все равно придется беспокоиться о том, создаете ли вы повторяющийся номер в та же нить . Это проблема для вас или нет?

1 голос
/ 28 марта 2010

Если вы действительно никогда не сможете повторить число между потоками или в одном потоке (эта часть не ясна на 100%), обычный генератор случайных чисел не будет работать для вас. Генератор, который создает число от 1 до N, имеет шанс 1 на N сгенерировать предыдущее число в следующий раз, когда его попросят об этом.

Если есть разумный верхний предел для общего числа случайных чисел, назовите его N, для конкретного запуска, вы можете рассмотреть возможность создания массива от 1 до N. Последовательно заполните этот массив числами от 1 до N, а затем используйте алгоритм перемешивания для сортировки чисел. Если у вас M потоков, вы можете затем сегментировать перемешанный массив так, чтобы первый поток использовал индексы 0, M, 2M; второй поток использует индексы 1, M + 1, 2M + 1 и т. д., гарантирующие, что вы не получите доступ за концом перетасованного массива.

Это решение с большим объемом памяти для довольно большого N, поэтому может не подойти для вашей проблемы. Если вам разрешено повторять одно и то же случайное число в заданном потоке, но не между потоками, решение Джона гораздо более дружественно к ресурсам.

...