【问题标题】:Thread safety of std::random_devicestd::random_device 的线程安全
【发布时间】:2017-06-28 16:24:11
【问题描述】:

我有一些看起来有点像这样的代码:

std::random_device rd;

#pragma omp parallel
{
    std::mt19937 gen(rd());
    #pragma omp for
    for(int i=0; i < N; i++)
    {
        /* Do stuff with random numbers from gen() */
    }
}

我有几个问题:

  • std::random_device 线程安全吗?即当多个线程同时调用它时它会做一些无用的事情吗?
  • 这通常是个好主意吗?我应该担心重叠的随机数流吗?
  • 有没有更好的方法来实现我想要的(每个线程中的独立随机数流 - 我现在不太担心可重复性)?

如果它对std::random_device 的工作有任何影响,我主要在 Windows 上运行,但我希望代码也能在 Linux 和 OSX 上同样良好地工作。

【问题讨论】:

  • 您可以实现重现性,但使用特定的种子而不是使用std::random_device
  • random_device 可能会被阻止。如果您想要的是并行性,那么这样使用它没有多大意义。您可以使用以random_device 为种子的全局 PRNG 来为mt19937 播种(但它需要显式锁定)。

标签: c++ c++11 random openmp


【解决方案1】:

并行使用随机设备不是一个好主意。即使它是阻塞的,您可能不会遇到重叠随机数流的问题,但是您添加了一个额外的同步点。

您应该设置与要启动的线程一样多的随机数引擎 (RNE),omp_get_num_threads()。 创建一个 RNE 的 std::vector 并将它们播种在程序的顺序部分中。对于播种,您可以使用随机设备和std::seed_seq

然后在每个线程中使用与线程号相关联的 RNE,omp_get_thread_num()

永远不要使用随机设备生成随机数,它的速度很慢,而且通常不会生成均匀分布的随机数!

根据您需要的随机数的质量,您可以使用预定义的随机数生成器之一。如果您正在进行蒙特卡罗模拟或密码学,请格外小心您选择的算法。

您可以在以下位置找到很多关于随机引擎的有用信息 https://en.cppreference.com/w/cpp/numeric/random.

【讨论】:

  • 您可能想用omp_get_max_threads() 实际查询线程数。当并行上下文用完时,omp_get_num_threads() 将始终返回 1。
【解决方案2】:

在没有 WinRT 的 Windows 上,它使用 CryptGenRandomhttps://stackoverflow.com/a/46171432/2024042 是线程安全的

在带有 WinRT 的 Windows 上,它使用 CryptographicBuffer::GenerateRandom。没有关于这个线程安全的文档,但它似乎没有状态。因此它应该是线程安全的。

在 Linux 上,它似乎从 /dev/urandom 读取,这是线程安全的。

我从libs/random/src/random_device.cpp 阅读了这个实现。

我不知道该文件中的_CXXRT_STD_NAME 是什么,谷歌搜索会产生 boost::random_device 作为唯一结果。也许没什么!

【讨论】:

    猜你喜欢
    • 2017-12-05
    • 1970-01-01
    • 2013-02-10
    • 2013-01-07
    • 1970-01-01
    • 2019-06-07
    • 2017-04-30
    相关资源
    最近更新 更多