我正在学习OpenMP,以下带有嵌套for循环的代码会给出意想不到的结果和线程数> 1.我希望只有外环在这里并行化,我希望有4行输出。我使用的是gcc 4.8.4。
#pragma omp parallel
{
const int nthreads = omp_get_num_threads();
const int ithread = omp_get_thread_num();
#pragma omp for
for (out = 0; out < 2; out++) {
for (in = 0; in < 2; in++) {
printf("id= %d of %d, out= %d, in= %d\n", ithread, nthreads, out, in);
}
}
}
如果我设置OMP_NUM_THREADS=1
,我会得到4行的预期输出:
id= 0 of 1, out= 0, in= 0
id= 0 of 1, out= 0, in= 1
id= 0 of 1, out= 1, in= 0
id= 0 of 1, out= 1, in= 1
但是,OMP_NUM_THREADS=2
错过了一行输出!
id= 0 of 2, out= 0, in= 0
id= 1 of 2, out= 1, in= 0
id= 0 of 2, out= 0, in= 1
将内循环设置为for (in = 0; in < 3; in++)
仅提供4行输出而不是预期的6!
id= 0 of 2, out= 0, in= 0
id= 1 of 2, out= 1, in= 0
id= 0 of 2, out= 0, in= 1
id= 1 of 2, out= 1, in= 2
我在这里做了什么非常错的事吗?请帮我解决这个问题。感谢。
答案 0 :(得分:0)
看起来你的内部循环变量是在并行块开始之前声明的。这意味着它在所有线程之间隐式共享。也许你正试图将2D循环并行化,但你所尝试的并不会实现这一点;相反,每个内部循环将以非确定性方式与其他正在运行的内部循环冲突。
如果要并行化2D循环,必须对所有元素使用单个循环,然后手动计算索引,例如: 正如高性能标记指出的那样,有一个专用的构造:OpenMP and nested loops? for(int i=0;i<2*2;i++){ int out=i/2; int in=i%2; ... }
。现在你可以在没有问题的情况下使i
并行循环。
如果您只使用并行化单个维度(这通常就足够了),您需要在并行循环中声明内部变量:
int out;
#pragma omp parallel for
for(out=0;out<2;out++){
int in;
for(in=0;in<2;in++){
// action
}
}
或明确标记内部变量private:
int in, out;
#pragma omp parallel for private(in)
for(out=0;out<2;out++){
for(in=0;in<2;in++){
// action
}
}
这两个都使外循环并行,并且内循环对每个线程都是私有的,从而防止一个线程的当前状态改变另一个线程的状态。如果你在c-c99之前,第二种风格很有用,但是我建议只是在循环中移动声明更能表现出意图。
此问题包含有关设置私有变量的一些有用说明:OpenMP: are local variables automatically private?
最后,您应该避免直接从多个线程打印到同一输出;这些函数的线程安全性是模糊的(虽然特别是在Linux上它似乎更好地定义)。最好将打印抽象为线程安全缓冲区并使用单个线程来写入缓冲区。
答案 1 :(得分:0)
我看到两个问题:
声明为私有(以便每个线程都有自己的副本)
#pragma omp parallel for private(in) /* each thread needs its own copy of in */
for (out = 0; out < 2; out++) {
for (in = 0; in < 2; in++) {
printf("id= %d of %d, out= %d, in= %d\n", ithread, nthreads, out, in);
}
}
}