I\'m trying to run several instances of a piece of code (2000 instances or so) concurrently in a computing cluster. The way it works is that I submit the jobs and the clust
A combination of the PID and the time should be enough to get a unique seed. It's not 100% cross-platform, but getpid(3) on *nix platforms and GetProcessId on Windows will get you 99.9% of the way there. Something like this should work:
srand((time(NULL) & 0xFFFF) | (getpid() << 16));
You could also read data from /dev/urandom
on *nix systems, but there's no equivalent to that on Windows.
Just an idea... generate a GUID (which is 16 bytes) and sum its 4-byte or 8-byte chunks (depending on the expected width of the seed), allowing integer wrap-around. Use the result as a seed.
GUIDs typically encapsulate characteristics of the computer that generated them (such as MAC address), which should make it rather improbable that two different machines will end-up generating the same random sequence.
This is obviously not portable, but finding appropriate APIs/libraries for your system should not be too hard (e.g. UuidCreate
on Win32, uuid_generate
on Linux).
unsigned seed;
read(open("/dev/urandom", O_RDONLY), &seed, sizeof seed);
srand(seed); // IRL, check for errors, close the fd, etc...
I would also recommend a better random number generator.
Provides CryptGenRandom()
and RtlGenRandom()
. They will give you an array of random bytes, which you can use as seeds.
You can find the docs on the msdn pages.
You can use Openssl's RAND_bytes()
to get a random number of bytes on linux. It will use /dev/random
by default.
#ifdef _WIN32
#include <NTSecAPI.h>
#else
#include <openssl/rand.h>
#endif
uint32_t get_seed(void)
{
uint32_t seed = 0;
#ifdef _WIN32
RtlGenRandom(&seed, sizeof(uint32_t) );
#else
RAND_bytes(&seed, sizeof(uint32_t) );
#endif
return seed;
}
Note that openssl provides a Cryptographically secure PRNG by default, so you could use it directly. More info here.
If C++11 can be used then consider std::random_device
. I would suggest you to watch link for a comprehensive guide.
Extracting the essential message from the video link : You should never use srand
& rand
, but instead use std::random_device
and std::mt19937
-- for most cases, the following would be what you want:
#include <iostream>
#include <random>
int main() {
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_int_distribution<int> dist(0,99);
for (int i = 0; i < 16; i++) {
std::cout << dist(mt) << " ";
}
std::cout << std::endl;
}
Instead of straight time as measured in seconds from the C std lib time() function, could you instead use the processor's counter? Most processors have a free running tick count, for example in x86/x64 there's the Time Stamp Counter:
The Time Stamp Counter is a 64-bit register present on all x86 processors since the Pentium. It counts the number of ticks since reset.
(That page also has many ways to access this counter on different platforms -- gcc/ms visual c/etc)
Keep in mind that the timestamp counter is not without flaws, it may not be synced across processors (you probably don't care for your application). And power saving features may clock up or down the processor (again you probably don't care).