【发布时间】:2018-10-25 12:15:31
【问题描述】:
我使用 rand() 函数生成 0,1 之间的伪随机数用于模拟目的,但是当我决定让我的 C++ 代码并行运行(通过 OpenMP)时,我注意到 rand() 不是线程- 安全,也不是很统一。
所以我转而使用(所谓的)更统一的生成器,这些生成器在其他问题的许多答案中都出现了。看起来像这样
double rnd(const double & min, const double & max) {
static thread_local mt19937* generator = nullptr;
if (!generator) generator = new mt19937(clock() + omp_get_thread_num());
uniform_real_distribution<double> distribution(min, max);
return fabs(distribution(*generator));
}
但我在模拟的原始问题中发现了许多科学错误。既违反rand()的结果又违反常识的问题。
所以我写了一个代码,用这个函数生成 500k 个随机数,计算它们的平均值,然后重复 200 次并绘制结果。
double SUM=0;
for(r=0; r<=10; r+=0.05){
#pragma omp parallel for ordered schedule(static)
for(w=1; w<=500000; w++){
double a;
a=rnd(0,1);
SUM=SUM+a;
}
SUM=SUM/w_max;
ft<<r<<'\t'<<SUM<<'\n';
SUM=0;
}
我们知道,如果不是 500k,我可以无限次执行它,它应该是一条值为 0.5 的简单线。但是 500k 我们会有 0.5 左右的波动。
单线程运行代码时,结果可以接受:
但这是 2 个线程的结果:
3 个线程:
4 个线程:
我现在没有我的 8 线程 CPU,但结果还是值得的。
如您所见,它们都不统一,并且在平均值附近波动很大。
那么这个伪随机生成器也是线程不安全的吗?
还是我在某个地方犯了错误?
【问题讨论】:
-
评论不用于扩展讨论;这个对话是moved to chat。
-
您是否尝试过为随机数生成器使用更好的种子?
-
@FrançoisAndrieux 你有什么建议?我认为时钟和线程号既是随机的又是线程安全的。
-
虽然没有直接关系:
rand()不需要 是线程安全的(cfr.POSIXstdlib.h) -
您编写的测试代码在
SUM...上存在竞争条件...
标签: c++ multithreading random openmp