Standard random functions are not thread safe. Calling them in parallel may result in undefined behavior or the threads blocking each other. This is a little test to create the same random sequences in serial as in parallel too.
Setting the same seed on a random generator as a start point should produce the same random sequence. First we create one generator and print the first three numbers. Restart it with different seed numbers.
Then we create three random generators with the same seeds and call them parallel. They should create the same sequences even if they are called interleaved.
Program output:
seriell
seed 1
48271
182605794
1291394886seed 2
96542
365211588
435306125seed 3
144813
547817382
1726701011parallel
Thread 0 seed 1: 48271
Thread 0 seed 1: 182605794
Thread 0 seed 1: 1291394886
Thread 1 seed 2: 96542
Thread 1 seed 2: 365211588
Thread 1 seed 2: 435306125
Thread 2 seed 3: 144813
Thread 2 seed 3: 547817382
Thread 2 seed 3: 1726701011
Yep, work as expected :D
The program looks not as simple as it might can be. But I think it is okay.
void waitlong() {
long a = 0;
for(int i=0; i < 1000000; i++) {
a += i;
}
}
int main() {
// create some random number and store them in expectedResult
int expectedResult[3][3] = { 0 };
std::minstd_rand generator;
std::cout << "seriell\n";
for(int id=0; id < 3; id++) {
generator.seed(id+1);
std::cout << "seed " << id+1 << "\n";
for(int i=0; i < 3; i++) {
expectedResult[id][i] = generator();
std::cout << expectedResult[id][i] << "\n";
}
}
// create three generators with the same seed and call them parallel
std::cout << "\nparallel\n";
std::minstd_rand generators[3];
generators[0].seed(1);
generators[1].seed(2);
generators[2].seed(3);
int result[3][3] = { 0 };
int count = 0;
// create 3 threads and interleave them with schedule(static, 1) num_threads(3)
// We can not call cout in a threaded enviroment. So we must store the random numbers
// in a array and print them laster. count and result is for this.
#pragma omp parallel for firstprivate(count) shared(result) schedule(static, 1) num_threads(3)
for(int i=0; i < 3*3; i++) {
int id = omp_get_thread_num();
int rand = generators[id]();
// not error free even with omp critical
// std::cout << "Thread " << id << " seed " << id+1 << ": " << rand << "\n";
result[id][count++] = rand;
// wait a litte bit to give the next thread a chance to start
waitlong();
}
// now print and compre the results
for(int id=0; id < 3; id++) {
for(int i=0; i < 3; i++) {
std::cout << "Thread " << id << " seed " << id+1 << ": " << result[id][i] << "\n";
if(result[id][i] != expectedResult[id][i]) {
std::cout << "but expected " << expectedResult[id][i] << "\n";
}
}
}
std::cout << "\nValues per seed must be equal\n";
return 0;
}