简体   繁体   中英

Why is rand() not so random after 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);
}

Prints the same (different on each run) number 10 times - expected ? I have a more complicated piece of code where each forked process runs in turn - no difference

The outputs must be the same. If two processes each seed the random number with the same seed and each call rand once, they must get the same result. That's the whole point of having a seed. All of your processes call srand with the same seed (because you only call srand once) and they all call rand once, so they must get the same result.

Uncommenting the srand won't make a difference because unless the number of seconds has changed, they will still give the same seed. You could do:

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

The rand() function is a pseudo-random number generator. This means that the sequence of numbers generated is deterministic, depending only upon the seed provided.

Because you are forking the same process 10 times, the state of the random number generator is the same for each child. The next time you call rand() you will get the same value.

By calling srand(time(NULL)) inside the child process, you are potentially helping but the granularity of time() is only 1 second, so all your children probably start inside the same second. Seeding with the same value generates the same pseudo-random sequence.

You could try seeding with a value that depends on the child number:

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

(I used i*2 in the event that time() advances by 1 second during the fork loop.)

If your code is running fast enough, srand() might be seeded with the exact same time for each fork. time() only changes every second.

The reason that even adding srand(time(NULL)); (the line inside the if block that you have commented) inside the loop isn't making a difference is because modern computers can execute that whole block extremely fast, and time counts in seconds. From the man pages:

time() returns the time as the number of seconds since the Epoch...

If you add a sleep(1); after the if statement in the while loop and uncomment the srand call, the results will be different, since time would now return a different value because a second has elapsed.

It would however be more appropriate to use a different seed value, rather than waiting. Something like i would be a good idea since it'll be unique for each iteration of the loop.

This solve the problem:

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

I havent tested with fork, but inside a for calling 100 times it works.

seed with the pid number. It's a little but difficult to solve problem.

This was in some page: "this worked srand(time(0)+getpid()); but I had to call this within the case 0 ie child process".

The reason for this is because all programs are seeded with the same value (outside that while loop). You should seed again once you've forked the new program or both will produce the same sequence.

You're not reseeding when you make a child process. The state of the random number generator is exactly the same.

Even if you seed again in your child, you're seeding with the time with a +/- 1 second granularity. When you fork, it all happens in less than a second.

Try seeding it with something different and more random.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM