我正在运行一个模拟,其中生成了许多随机数。 RNG实现为C ++对象,其具有返回随机数的公共方法。为了将它与OpenMP并行化一起使用,我只需创建一个这样的RNG对象数组,每个线程一个。然后,每个线程通过调用其中一个RNG生成自己的随机数。 E.g:
for (int i = 0; i < iTotThreads; i++) {
aRNG[i] = new RNG();
}
// ... stuff here
#pragma omp parallel
{
iT = omp_get_thread_num();
#pragma omp for
for ( /* big loop */) {
// more stuff
aRNG[iT]->getRandomNumber();
// more stuff
}
}
即使每个RNG都在自己的成员变量上运行,并且两个这样的RNG不适合单个缓存行(我也尝试在创建时明确地对齐每个RNG),但似乎存在一些错误的共享作为代码完全没有规模。
如果我在omp并行区域内实例化对象:
#pragma omp parallel
{
i = omp_get_thread_num();
aRNG[i] = new RNG();
}
代码完美地扩展。你知道我在这里缺少什么吗?
编辑:顺便说一句,在第二种情况下(缩放的那个),我创建RNG的并行区域与我使用它们的并行区域不同。我指望当我进入第二个平行区域时,aRNG[]
中的每个指针仍指向我的一个对象,但我想这是不好的做法......
答案 0 :(得分:4)
虽然我怀疑你的描述错误分享是导致问题的原因,但为什么不以这种方式简化代码:
// ... stuff here
#pragma omp parallel
{
RNG rng;
#pragma omp for
for ( /* big loop */) {
// more stuff
rng.getRandomNumber();
// more stuff
}
}
在parallel
区域rng
内声明将是具有自动存储持续时间的私有变量,因此:
如果这种方法不可行,并且遵循@HristoIliev的建议,您总是可以声明一个threadprivate
变量来保存指向随机数生成器的指针:
static std::shared_pointer<RNG> rng;
#pragma omp threadprivate(rng);
并在第一个并行区域中分配它:
rng.reset( new RNG );
在这种情况下,虽然有一些注意事项可以确保rng
的值在并行区域中保留(引用OpenMP 4.0标准):
非初始的threadprivate变量中的数据值 线程保证在两个连续活动之间保持不变 只有满足以下所有条件时才能使用并行区域:
- 两个并行区域都没有嵌套在另一个显式并行区域内。
- 用于执行两个并行区域的线程数相同。
- 用于执行两个并行区域的线程相关性策略是相同的。
- 在两个并行区域的入口处,封闭任务区域中dyn-var内部控制变量的值为false。
如果这些条件都成立,并且如果是一个threadprivate变量 在两个区域中引用,然后具有相同线程号的线程 在各自的地区将参考相同的副本 变量