Почему rand() не так случайен после fork?

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main() {
    int i =10;
    /* initialize random seed:  */
    srand(time(NULL));
    while(i--){
        if(fork()==0){
            /* initialize random seed here does not make a difference:
            srand(time(NULL));
             */
            printf("%d : %d\n",i,rand());
            return;
        }
    }
    return (EXIT_SUCCESS);
}

Печатает одинаковое (по-разному в каждом прогоне) число 10 раз - ожидаемое? У меня есть более сложная часть кода, где каждый разветвленный процесс запускается по очереди - без разницы

Ответ 1

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

Раскомментирование srand не будет иметь значения, поскольку, если количество секунд не изменилось, они все равно будут давать одно и то же семя. Вы можете сделать:

srand(time(NULL) ^ (getpid()<<16));

Ответ 2

Функция rand() является генератором псевдослучайных чисел. Это означает, что последовательность генерируемых чисел является детерминированной, в зависимости только от предоставленного семени.

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

Вызывая srand(time(NULL)) внутри дочернего процесса, вы потенциально помогаете, но зернистость time() составляет только 1 секунду, поэтому все ваши дети, вероятно, начнут с той же секунды. Сеяние с одинаковым значением генерирует одну и ту же псевдослучайную последовательность.

Вы можете попробовать посев со значением, которое зависит от дочернего номера:

srand(time(NULL) - i*2);

(я использовал i*2 в том случае, если time() продвигается на 1 секунду во время цикла fork.)

Ответ 3

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

Ответ 4

Причина, заключающаяся в том, что даже добавление srand(time(NULL)); (строка внутри блока if, которую вы прокомментировали) внутри цикла не влияет на то, что современные компьютеры могут выполнять весь этот блок очень быстро, а time рассчитывается в секундах. С man-страниц:

time() возвращает время как количество секунд с момента Epoch...

Если вы добавите sleep(1); после оператора if в цикле while и раскомментируете вызов srand, результаты будут разными, так как time теперь будет возвращать другое значение, потому что вторая имеет прошло.

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

Ответ 5

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

Ответ 6

Вы не пересаживаетесь, когда выполняете дочерний процесс. Состояние генератора случайных чисел точно такое же.

Даже если вы снова семяете у своего ребенка, вы посеяли время с зернистостью +/- 1 секунду. Когда вы используете fork, все это происходит менее чем за секунду.

Попробуйте посеять его чем-то другим и более случайным.

Ответ 7

Это решает проблему:

srand48((long int)time(NULL));
i= (lrand48()/rand()+1) % 123

Я не тестировался с помощью fork, но внутри a для вызова 100 раз он работает.

семя с номером pid. Это немного, но трудно решить проблему.

Это было на одной странице: "это сработало srand (time (0) + getpid()), но я должен был вызвать это в случае 0 i.e дочернего процесса".