首页 > 解决方案 > 如何使用多线程确定性 PRNG

问题描述

我使用 TBB 对我的应用程序的一部分进行多线程处理。
以下代码在逻辑上负责非确定性行为:

    std::mt19937 engine;
    std::uniform_real_distribution<double> distribution(-1., 1.);

    double x[N];

    tbb::parallel_for(0, N, [&](int i)
    {
        // ... complicated stuff done in this loop
        x[i] = distribution(engine);
    });

我将代码更改为每个线程使用一个 PRNG,使用 TBB TLS,并使用循环索引为 PRNG 播种。
它似乎有效,但对我来说看起来很奇怪。这是一种常见的做法吗?

    tbb::enumerable_thread_specific<std::mt19937> engine;
    std::uniform_real_distribution<double> distribution(-1., 1.);

    double x[N];

    tbb::parallel_for(0, N, [&](int i)
    {
        // ... complicated stuff done in this loop
        engine.local().seed(i);
        x[i] = distribution(engine.local());
    });

标签: c++randomtbb

解决方案


我没有使用过这个特定的并行化库。但是,使用多线程

  • 必须阅读有关您使用的函数的文档,它们通常不是线程安全的,除非明确声明它是线程安全的。
  • 保护数据免受并发访问。例如,通过互斥体或线程屈服构造。

这是一个使用互斥锁/锁的例子

static std::mt19937 engine(std::random_device{}());
std::uniform_real_distribution<double> distribution(-1., 1.);
std::mutex mtx;

double x[N];

tbb::parallel_for(0, N, [&](int i)
{
    // ... complicated stuff done in this loop

    // extra scope to manage lifetime of lock
    {
        std::unique_lock<std::mutex> lock(mtx);
        x[i] = distribution(engine);
    }
});

也许你必须为引擎种子做类似的事情,这也可能不是线程安全的。


推荐阅读