4

I am trying to spawn n child processes, then let each child process request a random number of resources. However, each child currently requests an identical number of resources, though that number changes each time I run the program.

/* Create the appropriate number of processes */
int pid;
for(int i = 0; i < numberOfProcesses; i++){
    pid = fork();
    if(pid < 0){
        fprintf(stderr, "Fork Failed");
        exit(1);
    }
    else if(pid == 0){
        time_t t;
        srand((unsigned) time(&t));

        printf("Child (%d): %d.", i+1, getpid());

        /* Generate a random number [0, MAX_RESOURCES] of resources to request */

        int requestNum = rand() % (MAX_RESOURCES + 1);
        printf(" Requesting %d resources\n", requestNum);

        exit(0);
    }
    else{ wait(NULL); }
}

UPDATE: The following seems to have solved the issue. Thank you for the help, those who commented!

time_t t;
srand((int)time(&t) % getpid());
Mitchell Griest
  • 467
  • 1
  • 7
  • 21
  • Print the value you pass to `srand`: `(unsigned) time(&t)`; and it should answer your question. Not having a fully reproducible code (main is missing) I assume that the seed is the same for all processes. This can happen when all the `fork` calls complete in the same second. – arielf Feb 26 '16 at 01:37
  • Note that `(int)time(&t) % getpid()` is a poor seed; if you need the numbers to be *really* random, then don't use that. – user253751 Feb 26 '16 at 01:55
  • 1
    @immibis If you need the numbers to be _really_ random, you wouldn't be using `rand()` at all, even _with_ a good seed. – e0k Feb 26 '16 at 02:23
  • Note that using `time(0) % getpid()` reduces the range of possible seed value dramatically, which in turn reduces the amount of randomness in the numbers generated by the child processes. Since PIDs are normally limited to either 64K (16 bits) or 100K (17 bits), you've typically reduced the seed range from 31 bits to 16 or 17 bits. However, for most plausible circumstances, you will get different numbers from each child. See also [`srand()` — why call it only once](http://stackoverflow.com/questions/7343833/srand-why-call-it-only-once/) per process for some more information. – Jonathan Leffler Feb 26 '16 at 02:40
  • Suggest `srand((unsigned)time(&t) ^ getpid());` – chux - Reinstate Monica Feb 26 '16 at 03:03

1 Answers1

7

You are seeding the random number generator with the current time. It's the same time for all children. You are forking child processes, which are checking the clock in parallel. The whole point of parallelism is to do multiple things at the same time.

From man time():

time() returns the time as the number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC).

Notice that this is also in seconds. A second is a very long time for a running process. Even if you tried this sequentially (not parallel) over and over, it would be highly likely that two processes would ask for the time, and get the same result.

Design a better way to seed your random number generator based on something unique to each process. You could, for example, add the process ID of the child to the seed (getpid(), not pid).

e0k
  • 6,961
  • 2
  • 23
  • 30
  • You should probably put in the obligatory quick explanation saying code is fast and seconds are slow etc etc. – Fantastic Mr Fox Feb 26 '16 at 01:40
  • Also, there is only one seed; all threads share it. If you want every thread to have an *independent* random number sequence, use rand_r (which also avoids mutex contention on the random number seed, for the majority of standard libraries with threadsafe rand implementations). – rici Feb 26 '16 at 02:49
  • @rici These are separate _processes_, not threads. They don't share the seed. But for a thread situation, that is a good point. – e0k Feb 26 '16 at 02:49
  • Oops. Quite right, shouldn't skim. – rici Feb 26 '16 at 02:53