如何让每个线程在C ++ 11中使用自己的RNG

时间:2013-04-10 06:42:49

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

我在C ++ 11中使用新的随机数生成器。虽然有不同的意见,但从这个thread看来,大多数人认为他们不是线程安全的。因此,我想制作一个程序,每个线程都使用自己的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?如果没有,我可以看一个如何完成这个的例子,或者参考一些他们解释如何实现这个目的的地方吗?

2 个答案:

答案 0 :(得分: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++;
     }
}

答案 1 :(得分:2)

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

我会建议一些久经考验的解决方案,例如this