C++Guns – RoboBlog

21.04.2015

Calling multiple random generator in parallel c++11

Filed under: Allgemein — Tags: — Thomas @ 00:04

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
1291394886

seed 2
96542
365211588
435306125

seed 3
144813
547817382
1726701011

parallel
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;
}

No Comments

No comments yet.

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

Powered by WordPress