我在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?如果没有,我可以看一个如何完成这个的例子,或者参考一些他们解释如何实现这个目的的地方吗?
答案 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