我需要迭代一个数组并根据需要一些迭代的计算来分配每个元素。删除所有不必要的细节,程序归结为类似的东西。
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
指令。另一方面,我不想在相同的j
上意外地允许线程针对不同的i
值运行,因为这会引入竞争条件。我还不确定是否需要一些关于如何处理这两个数组的额外规范。
最后,如果这个代码在一个将被重复调用的函数中,它是否需要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);
}
...
}
我查看了其他各种问题,但他们是关于不同种族条件的不同问题,我对如何概括答案感到困惑。
答案 0 :(得分:0)
您不希望omp parallel
中有main
。您使用的omp for
将仅为以下for (int i
循环创建/重用线程。对于i
的任何特定值,j
循环将完全在一个线程上运行。
另一件有用的事情是将output[i]
结果计算到局部变量中,然后在output[i]
循环完成后将其存储到j