3

How can I generate random numbers in C for multiple processes being run at exactly the same time?

I wanted to use srand and rand but I don't know how (maybe using the process ID?).

Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254
Shark
  • 301
  • 2
  • 5
  • 11

2 Answers2

13

You can use a different seed for each process, based on the process id for example :

srand(getpid());

And then just use rand().

Julien Fouilhé
  • 2,583
  • 3
  • 30
  • 56
  • 4
    Or why not combine time and pid for the seed: `srand(getpid() * time(NULL));` – Some programmer dude Sep 14 '12 at 10:32
  • @JoachimPileborg Yes, that can be a good idea too, but that's not an obligation so I took the easier way ;) – Julien Fouilhé Sep 14 '12 at 11:37
  • @Someprogrammerdude, what's the different seeding along with time(NULL) if concurrently executing? – ReneWang May 05 '17 at 06:17
  • 1
    @ReneWang The `rand` and `srand` functions are not reentrant, if you call `srand` with different values in different threads then each call will overwrite the stored seed from a previous call and you will have data-races. Also since `time` usually have only second resolution calling `time(NULL)` multiple times in a single second will give the same result, which can cause multiple processes to use the same seed and the same "random" sequence". – Some programmer dude May 16 '17 at 17:01
1

After years and years of weird errors from poor random seeds, I eventually wrote a code to get random numbers from /dev/urandom, which are the same random numbers used for SSL. In my code I used these "good" random numbers to seed the C stdlib rand() function, which was sufficent for my task as long as it got a good seed:

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

//HOW MANY BITS IN A CHAR? THIS MACRO IS USUALLY DEFINED
#ifndef CHAR_BIT
#define CHAR_BIT 8
#endif

//PATH TO RANDOM NUMBER GENERATOR
const char inPath[]="/dev/urandom";

//EXTRACTS A PSEUDORANDOM unsigned long FROM THE OPERATING SYSTEM VIA /dev/urandom
unsigned long get_urandom(){

  //OPEN INPUT STREAM
  FILE *inFile;
  inFile=fopen(inPath,"r");

  //FAILED TO OPEN STREAM
  if(inFile==NULL){
    fprintf(stderr, "# Failed to open random device %s\n", inPath);
    return 0;
  }

  //HOW MANY BITS IN A CHAR? HOW MANY CHARS IN AN UNSIGNED LONG?
  const int bitsInChar  = CHAR_BIT;
  const int charsInLong = sizeof(unsigned long) / sizeof(char);

  //GET RANDOM UNSIGNED LONG ONE CHARACTER AT A TIME
  unsigned long randomSeed=0;
  for(int i=0; i<charsInLong; i++)
    randomSeed |= fgetc(inFile) << i*bitsInChar;

  //CLOSE STREAM AND RETURN
  fclose(inFile);
  return randomSeed;

}

int main(){

  // We can use the above function directly to get our random numbers, but this is slow.
  printf("We can get random numbers from the OS via get_urandom: %u\n", get_urandom());  

  // Or we can just call get_urandom once, to use as a seed for the stdlib rand() function.
  unsigned int randomSeed=get_urandom();
  srand(randomSeed);
  printf("Or, using a random seed from get_urandom: %u\n", randomSeed);
  printf("We can get random numbers from stdlib, e.g.: %u\n", rand());
}

Here's the same code again with the function rewritten in C++:

#include <fstream>
using namespace std;

//HOW MANY BITS IN A CHAR? THIS MACRO IS USUALLY DEFINED
#ifndef CHAR_BIT
#define CHAR_BIT 8
#endif

//EXTRACTS A PSEUDORANDOM unsigned long FROM THE OPERATING SYSTEM VIA /dev/urandom
unsigned long get_urandom(const char inPath[]="/dev/urandom"){

  //OPEN INPUT STREAM
  ifstream inFile(inPath);

  //FAILED TO OPEN STREAM
  if(inFile.fail()){
    fprintf(stderr, "# Failed to open random device %s\n", inPath);
    return 0;
  }

  //HOW MANY BITS IN A CHAR? HOW MANY CHARS IN AN UNSIGNED LONG?
  const int bitsInChar  = CHAR_BIT;
  const int charsInLong = sizeof(unsigned long) / sizeof(char);

  //GET RANDOM UNSIGNED LONG ONE CHARACTER AT A TIME
  unsigned long randomSeed=0;
  for(int i=0; i<charsInLong; i++)
    randomSeed |= inFile.get() << i*bitsInChar;

  //CLOSE STREAM AND RETURN
  inFile.close();
  return randomSeed;

}

int main(){

  // We can use the above function directly to get our random numbers, but this is slow.
  printf("We can get random numbers from the OS via get_urandom: %u\n", get_urandom());  

  // Or we can just call get_urandom once, to use as a seed for the stdlib rand() function.
  unsigned int randomSeed=get_urandom();
  srand(randomSeed);
  printf("Or, using a random seed from get_urandom: %u\n", randomSeed);
  printf("We can get random numbers from stdlib, e.g.: %u\n", rand());
}
Douglas B. Staple
  • 10,510
  • 8
  • 31
  • 58