用于C++对象数组上循环的OpenMP
OpenMP for loop on array of C++ objects
我正在运行一个模拟,其中生成了许多随机数。RNG被实现为具有返回随机数的公共方法的C++对象。为了将它与OpenMP并行化一起使用,我只需创建一个这样的RNG对象数组,每个线程一个。然后,每个线程通过调用其中一个RNG来生成自己的随机数。例如:
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不适合在一个缓存行中(我在创建时也尝试过明确地对齐它们中的每一个),但似乎存在一些错误的共享,因为代码根本不可伸缩。
如果我实例化omp并行区域内的对象:
#pragma omp parallel
{
i = omp_get_thread_num();
aRNG[i] = new RNG();
}
代码的伸缩性非常好。你知道我在这里缺了什么吗?
编辑:顺便说一下,在第二种情况下(比例很好的情况),我创建RNG的平行区域与我使用它们的区域不同。当我进入第二个平行区域时,aRNG[]
中的每个指针仍然会指向我的一个对象,但我想这是一种糟糕的做法。。。
尽管我从您的描述中怀疑错误共享是问题的原因,但为什么不以这种方式简化代码呢:
// ... 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变量在两个区域中引用,然后使用相同线程号的线程在各自的地区将引用相同的副本变量
- 如何使用OpenMP并行这两个循环
- 如何使用OpenMP使这个循环并行
- 如何通过替换顺序代码的while循环来添加OpenMP for循环
- 使用输入打破 OpenMP 中的循环
- OpenMP for 循环并行性问题
- OpenMP:for 循环避免数据竞争,而无需使用关键
- 任务内部的 OpenMP 任务循环
- Pybind11:使用 for 循环使用 OpenMP 访问 python 对象
- OpenMP 内部的函数调用用于循环
- 如何使用 OpenMP 正确并行化 for 循环?
- 为什么 std::chrono 在测量循环和编译器优化的并行 OpenMP 的执行时间时不起作用?
- 如何使用 OpenMP 减少嵌套循环?
- 具有动态数组分配的OpenMP嵌套循环
- OpenMP 和不平衡嵌套循环
- OpenMP 嵌套循环处理性能
- 使用与 openmp C++并行的循环计算矩阵中每一行的最小值
- 嵌套循环 OpenMP 并行化、私有索引还是公共索引?
- 在 C++ 中使用 OpenMP 并行化两个 for 循环不会提供更好的性能
- OpenMP C++:并行化 for 循环的负载不平衡
- 优化依赖循环openmp