случайные числа и несколько вызовов srand

Я пишу программу, которая будет генерировать множество случайных чисел в циклах. Я пытаюсь сделать числа несколько менее предсказуемыми (не только для безопасности, но и для избежания столкновений на нескольких потоках).

Я заметил, что многие документы рекомендуют звонить srand только один раз в программе. Например: случайные числа в C выбранный ответ", как правило, только вызов srand() один раз в вашей программе".

но почему? С чего бы это? так плохо делать что-то вроде этого:

int THIS_THREAD_SEED;
int randomness() {
    ++THIS_THREAD_SEED;
    int i;
    for(i=0 i<1000; i++) {
        unsigned n = rand_r(&THIS_THREAD_SEED) / RAND_MAX;
        /* do something with n */
    }
    return 0;
}

int do_something() {
    int i;
    for(i=0; i<1000; i++) {
        randomness();
    }
}

таким образом, семя изменяется один раз за вызов функции, а не один раз за программу. Таким образом, независимо от того, сколько потоков запущено, ни один из двух потоков не будет иметь одного и того же списка случайных чисел... Правильно?

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

3 ответов


давайте разделим этот вопрос на два отдельных.

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

  2. Если вы думаете о вызове srand() несколько раз, пожалуйста, не надо. причина этого-процедура инициализации случайного генератора, которая устанавливает переменные на основе seed, имеет худшие случайные характеристики, дает худшую производительность, чем сам генератор случайных чисел, и не должен использоваться в качестве замены.


srand() будет сброс поток цифр rand() будет генерировать для вас.

из руководства для srand:

   The srand() function sets its argument as the seed for a  new  sequence
   of  pseudo-random  integers  to be returned by rand().  These sequences
   are repeatable by calling srand() with the same seed value.

Если вам нужны" лучшие " случайные числа, то rand () предоставляет вам следует изучить другие источники случайности.

и srand() не используется для rand_r(), аргумент, который вы предоставляете (to rand_r()) используется вместо этого.

и если вы хотите использовать rand_r() из нескольких потоков все потоки должны иметь локальное семя, для этого не следует использовать одну глобальную переменную.

альтернативы rand() может быть Мерсенн Твистер

но если вам нужна "реальная" случайность, вам нужно посмотреть аппаратную поддержку.

и в ответ:

таким образом, семя изменяется один раз за вызов функции, а не один раз за программу. Таким образом, независимо от того, сколько потоков работает, ни один из двух потоков не будет иметь одного и того же случайного список номеров... Правильно?

нет, не работает таким образом, у вас должна быть локальная переменная SEED, инициализированная чем-то уникальным для каждого потока. Вы могли бы использовать time() для первого семени, а затем используйте эту случайную последовательность для генерации семян для других потоков, или Вы читаете 4-8 байтов из /dev/random или /dev/urandom если вы используете *nix.

надеюсь, что дает некоторое представление, как это полуночный грохот, Спокойной ночи


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