【问题标题】:c++ generate thread safe random numbersc++ 生成线程安全的随机数
【发布时间】:2020-01-31 03:05:00
【问题描述】:

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

我正在尝试并行化需要重复生成一组随机数的参数扫描。我目前只有一个线程做这样的事情:

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 来节省自己的时间吗?谢谢。

【问题讨论】:

  • 由于您尚未展示您的scan() 功能,我们无法对其发表评论。但只要每个线程都拥有它自己的专属MyRNG 和分布,那么就没有理由担心它们会在线程之间共享。
  • Scan() 将与 main() 相同。

标签: c++ multithreading random thread-safety


【解决方案1】:

我可能会在main 中生成种子,并将种子传递给每个线程函数。我也不会直接使用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 的多个输出来创建种子。

哦,鉴于您的两个 uniform_real_distribution 实例使用相同的参数,可能也不需要两个单独的分发对象。

【讨论】:

    猜你喜欢
    • 2012-02-07
    • 1970-01-01
    • 1970-01-01
    • 2015-06-24
    • 1970-01-01
    • 2012-03-07
    • 1970-01-01
    • 1970-01-01
    • 2017-04-20
    相关资源
    最近更新 更多