7

我在 C++11 中使用新的随机数生成器。尽管有不同的意见,但从这个线程来看,似乎大多数人认为它们不是线程安全的。因此,我想制作一个程序,其中每个线程都使用自己的 RNG。

在有关如何使用 OpenMP 完成此操作的相关讨论中给出了一个示例:

#include <random>
#include <iostream>
#include <time.h>
#include "omp.h"

using namespace std;



int main()
{
    unsigned long long app = 0;
    {
        //mt19937_64 engine((omp_get_thread_num() + 1)); //USE FOR MULTITHREADING
        mt19937_64 engine; //USE FOR SINGLE THREAD
        uniform_real_distribution<double> zeroToOne(0.0, 1.0);

        //#pragma omp parallel for reduction(+:app) //USE FOR MULTITHREADING
        for (unsigned long long i = 0; i < 2000000000; i++)
        {
            if(zeroToOne(engine) < 0.5) app++;
        }
    }
    cout << app << endl;
    return 0;
}

当我运行该程序的多线程和单线程版本并跟踪时间时,它们在执行后需要相同的时间才能完成。另外,app两种情况下的大小不一样,但我怀疑这仅仅是因为种子不同。

问题:提供的示例是否正确显示了如何强制每个线程使用自己的 RNG?如果没有,我可以看到一个如何做到这一点的例子,或者获得他们解释如何实现这一点的某个地方的参考吗?

4

2 回答 2

6

您不能在多个线程之间共享随机引擎的实例。您应该锁定单个引擎或为每个线程创建一个引擎(使用不同的种子(请注意 e4e5f4 关于创建并行 MT 引擎的答案))。在 OpenMP 的情况下,您可以轻松地将每个线程的一个引擎存储在一个向量中,并通过omp_get_thread_num()位于 0 和omp_get_num_threads()–1.

class RNG
{
public:
    typedef std::mt19937 Engine;
    typedef std::uniform_real_distribution<double> Distribution;

    RNG() : engines(), distribution(0.0, 1.0)
    {
        int threads = std::max(1, omp_get_max_threads());
        for(int seed = 0; seed < threads; ++seed)
        {
            engines.push_back(Engine(seed));
        }
    }

    double operator()()
    {
        int id = omp_get_thread_num();
        return distribution(engines[id]);
    }

    std::vector<Engine> engines;
    Distribution distribution;
};

int main()
{
     RNG rand;
     unsigned long app = 0;

     #pragma omp parallel for reduction(+:app)
     for (unsigned long long i = 0; i < 2000000000; i++)
     {
         if(rand() < 0.5) app++;
     }
}
于 2013-04-10T07:40:03.840 回答
2

我会避免使用随机播种。它最终可能会出现重叠的流。这最终会影响最终的统计数据。

我会建议一些像这样久经考验的解决方案

于 2013-04-10T09:55:10.013 回答