Reputation: 321
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?).
Upvotes: 3
Views: 4850
Reputation: 10946
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());
}
Upvotes: 1
Reputation: 2658
You can use a different seed for each process, based on the process id for example :
srand(getpid());
And then just use rand()
.
Upvotes: 13