【问题标题】:Thread-safe random number generator with openMP使用 openMP 的线程安全随机数生成器
【发布时间】:2017-04-20 11:40:28
【问题描述】:

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

#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 相同的输出。

【问题讨论】:

  • 你能更清楚你想做什么吗?显然,产生一系列输出的 PRNG 只能按顺序产生这些输出。你想要什么?
  • @DavidSchwartz 我编辑了这篇文章,希望让它更清楚。我正在尝试创建一个确定性过程,该过程采用随机种子并以多线程方式生成随机数。可能吗?我不确定我的评论是否有助于您理解。您能否更具体地说明不清楚的地方?
  • 线程到底在做什么?为了使结果具有确定性,必须有一个到达某个特定位置的第一个结果。然后,只有这样,才会有第二个结果。正确的?看来您既要求以精确的顺​​序(一个,然后是下一个,等等)做事,又要求以多线程的方式来做。
  • 您只能获得每个线程的确定性输出。这是因为您无法保证每个线程生成随机数的顺序。显然,共享 PRNG 将为您提供确定性的数字序列(前提是您“破坏”线程以使其线程安全);但由于哪个线程得到哪个数字不是确定性的,所以从随机数推导的任何推导也不是确定性的。 您唯一合理的选择是为每个线程使用单独的 PRNG 实例
  • @CraigYoung 好的,所以不可能确保./test 87 1 200 提供与./test 87 3 200 相同的输出,但如果我们定义一个可以确保./test 87 3 200 系统地提供相同的输出PRNG 从每个线程的主 PRNG 的值中播种。休息一下,看看 openMP 是否可以做到这一点。谢谢

标签: c++ multithreading random openmp generator


【解决方案1】:

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

【讨论】:

  • 您能否总结一下为什么线程本地RNG实例不是做到这一点的最佳方式,如何在概念上做得更好?图书馆链接很棒,我相信文档也是如此,但在答案中也有这个很重要。
【解决方案2】:

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

要么使用某种锁定来包装该对象的访问,要么为每个线程提供一个单独的实例 [EDIT] 以不同的方式播种(可能来自您创建的 mt19937 的第一个实例),以便每个实例给出不同的结果 [/EDIT ](如果使用 omp 可以实现的话)。

【讨论】:

  • 感谢您的回答。使用 openMP 可以进行锁定(因为可以阅读 here),但我不太明白它的含义。另外,当您说“提供单独的实例”时,您能否更具体一点?如果我只是复制mt,那么每个线程都会产生完全相同的输出。这将不同于单线程进程将产生的结果,并且会导致 store 中的重复值,这是不可取的。可以扩展一下吗?
猜你喜欢
  • 1970-01-01
  • 2012-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-31
  • 1970-01-01
  • 1970-01-01
  • 2012-03-07
相关资源
最近更新 更多