带有openMP的线程安全随机数生成器

时间:2016-12-05 23:16:06

标签: c++ multithreading random openmp generator

以下简单脚本并行生成随机数

#include <random>
#include <iostream>
#include <omp.h>

int main(int argc, char *argv[])
{
  // Three integers are expected from the command line.
  // The first integer is a random seed
  // The second integer is the number of threads.
  // The third integer indicates the number of random numbers to produce

  // Read the seed and create the random number generator and the random distribution
  int seed = std::stoi(argv[1]);
  std::mt19937 mt(seed);
  std::uniform_real_distribution<float>  dist(0, 100);

  // Read the number of threads and set it.
  int nbThreads = std::stoi(argv[2]);
  omp_set_num_threads(nbThreads);

  // Number of random number for demonstration
  int n = std::stoi(argv[3]);

  // Will store the random number to print them conveniently
  std::vector<float> store(n);

  // produce 'n' random numbers
  #pragma omp parallel for
  for (int i = 0 ; i < n ; ++i)
  {
    store[i] = dist(mt);
  }

  // print the random numbers
  for ( auto& rnd : store )
  {
    std::cout << rnd << std::endl;
  }

  return 0;
}

使用单个线程时,上述脚本是确定性的

./test 3 1 2
55.0798
7.07249

./test 3 1 2
55.0798
7.07249

./test 7 1 2
7.63083
22.7339


./test 7 1 2
7.63083
22.7339

然而,当使用多个线程时,它是部分随机的并且包含线程之间的相关性(这可能是一个非常大的问题)

./test 3 2 2
43.1925
43.1925

./test 3 2 2
55.0798
7.07249

 ./test 7 2 2
22.7339
7.63083

./test 7 2 2
7.63083
7.63083

我理解为什么我的代码不是线程安全的,但我不明白如何使其成为线程安全的。是否有可能具有确定性输出而不管线程数?

目标是./test 87 1 200产生与./test 87 3 200相同的输出(即线程数不会影响对象store)。如果无法做到这一点,那么目标是./test 87 3 200产生与./test 87 3 200相同的输出。

2 个答案:

答案 0 :(得分:1)

您正在std::mt19937 mt对象中与每个线程共享状态,这不是线程安全的。

使用某种类型的锁定来包装该对象的访问,或者为每个线程[EDIT]提供单独的实例(可能来自您创建的mt19937的第一个实例),以便每个实例提供不同的结果[/ EDIT ](如果有任何可能使用omp)。

答案 1 :(得分:0)

提供两个不同的mt19937实例(每个线程一个,以不同的方式播种)并不是最好的方法。在线程环境中有一个专用于RNG的库,您可以找到here。请务必阅读文档,写得非常好,特别是2.2节。