在并行化之前,我在循环之外创建了一个default_random_engine
对象,因为创建这样的对象并不便宜。我在循环中重复使用它。
当与OpenMP
并行化时,我注意到uniform_dist(engine)
对随机引擎进行了可变引用,我认为它不是线程安全的。
该程序并没有崩溃,但我担心它的正确性。
我假设random_device
是线程安全的,所以我可以在循环中移动default_random_engine
的定义但是我不想在每次迭代时创建一个随机引擎对象,因为我读到了这并不便宜。
我认为另一种方法是创建default_random_engine
个对象的数组(大小:线程数),并使用OpenMP函数在每次迭代开始时根据线程ID选择正确的对象
有更好的方法吗?
#include <iostream>
#include <random>
using namespace std;
int main() {
int N = 1000;
vector<int> v(N);
random_device r;
default_random_engine engine(r());
#pragma omp parallel for
for (int i = 0; i < N; ++i) {
uniform_int_distribution<int> uniform_dist(1, 100);
// Perform heavy calculations
v[i] = uniform_dist(engine); // I assume this is thread unsafe
}
return 0;
}
答案 0 :(得分:1)
由于实际代码将随机引擎传递给许多函数(每个函数生成来自不同发行版的整数和实数),我每个线程都使用了生成器数组,因为它对代码库的修改最少:
#include <iostream>
#include <omp.h>
#include <vector>
#include <random>
using namespace std;
int main() {
random_device r;
std::vector<std::default_random_engine> generators;
for (int i = 0, N = omp_get_max_threads(); i < N; ++i) {
generators.emplace_back(default_random_engine(r()));
}
int N = 1000;
vector<int> v(N);
#pragma omp parallel for
for (int i = 0; i < N; ++i) {
// Get the generator based on thread id
default_random_engine& engine = generators[omp_get_thread_num()];
// Perform heavy calculations
uniform_int_distribution<int> uniform_dist(1, 100);
v[i] = uniform_dist(engine); // I assume this is thread unsafe
}
return 0;
}
请记住,此代码假定函数omp_set_num_threads
永远不会在程序中被调用。如果发生这种情况,线程可能会得到比旧omp_get_thread_num()
更大的数字(omp_get_max_threads()
),这会导致缓冲区溢出错误。
遗憾的是,此解决方案假定标准as explained in this other comment不需要实现细节。