c ++生成线程安全随机数

问题描述 投票:0回答:1

我已经阅读了与我要问的问题类似的问题,但是答案对我来说似乎并不完整或不完全清楚。

我正在尝试并行化参数扫描,该参数扫描需要重复生成一组随机数。目前,只有一个线程可以执行以下操作:

int main() {
  //Get random number generators
  typedef std::mt19937 MyRNG;
  std::random_device rd;

  //seed generator
  MyRNG rng;
  rng.seed(rd());

  //make my uniform distributions for each parameter
  std::uniform_real_distribution<> param1(-1,1);
  std::uniform_real_distribution<> param2(-1,1);

  double x,y;
  //Do my scan
  for (int i = 0; i < N; i++) {
    x = param1(rng)
    y = param2(rng)

   //Do things with x and y*
  }

这样,每次扫描都会得到一个新的x和y。现在,我想利用多个内核并行执行此操作。因此,我定义了一个函数void scan(),该函数基本上与我的主要函数具有相同的内容。然后,我创建多个线程,每个线程都运行scan()。但是我不确定使用std :: thread是否是线程安全的。我现在在每个线程中生成的随机数是否是独立的?我可以通过在void函数之外创建我的RNG来节省时间吗?谢谢。

c++ multithreading random thread-safety
1个回答
0
投票

我可能会在main中生成seeds,并将种子传递给每个线程函数。我也不会直接使用std::random_device的输出-我将数字放到std::setstd::unordered_set之类的东西中,直到获得想要的种子数为止,以确保不会给两个线程相同的种子(这显然会浪费时间)。

这条基本思路:

int do_work(unsigned long long seed) {

  //Get random number generators
  typedef std::mt19937 MyRNG;

  //seed generator
  MyRNG rng(seed);

  //make my uniform distributions for each parameter
  std::uniform_real_distribution<> param1(-1,1);
  std::uniform_real_distribution<> param2(-1,1);

  double x,y;
  //Do my scan
  for (int i = 0; i < N; i++) {
    x = param1(rng);
    y = param2(rng);

   //Do things with x and y*
  }
}

static const int num_threads = 4;

int main() {
    std::set<unsigned long long> seeds;

    while (seeds.size() < num_threads)
       seeds.insert(std::random_device()());

    std::vector<std::thread> threads;

   for (auto const seed: seeds)
       threads.emplace_back(std::thread(do_work, seed));

    for (auto &t : threads)
        t.join();
}

此外,使用random_device的单个结果作为std::mt19937的种子会限制生成器的相当一部分-您只给它32(或可能是64)位种子,但实际上它有19937位种子材料。 std::seed_seq尝试至少在某种程度上加以改善(除其他外,您可以使用std::random_device的许多输出来创建种子。

© www.soinside.com 2019 - 2024. All rights reserved.