用于在一维数组上嵌套循环操作的正确 openmp 指令

Proper openmp directives for nested for loop operating on 1D array

本文关键字:openmp 指令 操作 一维数组 嵌套循环 用于      更新时间:2023-10-16

我需要迭代一个数组,并根据需要一些迭代本身的计算来分配每个元素。删除所有不必要的细节,程序归结为这样的东西。

float output[n];
const float input[n] = ...;
for (int i = 0; i < n; ++i) {
output[i] = 0.0f;
for (int j = 0; j < n; ++j) {
output[i] += some_calculation(i, input[j]);
}
}

some_calculation不会更改其参数,也不会具有内部状态,因此其线程是安全的。查看循环,我知道外部循环是线程安全的,因为不同的迭代输出到不同的内存位置(不同的output[i](,并且在循环运行时永远不会更改input的共享元素,但内部循环不是线程安全的,因为它在output[i]上具有竞争条件,因为它在所有迭代中都会更改。

因此,我想生成线程并让它们为不同的i值工作,但input的整个迭代应该是每个线程的本地,以免在output[i]上引入竞争条件。我认为以下内容可以实现这一点。

std::array<float, n> output;
const std::array<float, n> input[n];
#pragma omp parallel for
for (int i = 0; i < n; ++i) {
output[i] = 0.0f;
for (int j = 0; j < n; ++j) {
output[i] += some_calculation(i, input[j]);
}
}

我不确定这是如何处理内部循环的。在不同i上工作的线程应该能够并行运行循环,但我不明白我是否允许它们在没有另一个#pragma omp指令的情况下运行。另一方面,我不想意外地允许线程在同一i上以不同的j值运行,因为这会引入竞争条件。我也不确定我是否需要一些关于如何处理这两个数组的额外规范。

最后,如果此代码位于将要重复调用的函数中,它是否需要parallel指令,或者是否可以在我的主循环开始之前调用一次。

void iterative_step(const std::array<float, n> &input, const std::array<float, n> &output) {
// Threads have already been spawned
#pragma omp for
for (int i = 0; i < n; ++i) {
output[i] = 0.0f;
for (int j = 0; j < n; ++j) {
output[i] += some_calculation(i, input[j]);
}
}
int main() {
...
// spawn threads once, but not for this loop
#pragma omp parallel
while (...) {
iterative_step(input, output);
}
...
}

我浏览了其他各种问题,但它们是关于不同竞争条件下的不同问题,我对如何概括答案感到困惑。

你不希望omp parallelmain。 您使用的omp for将仅为以下for (int i循环创建/重用线程。 对于任何特定的i值,j循环将完全在一个线程上运行。

另一件有帮助的事情是将output[i]结果计算成局部变量,然后在完成j循环后将其存储到output[i]中。