我想知道使用OpenMP的for循环的进展。 我知道减少指令不起作用,但我写的是这样的:
#pragma omp for reduction (+:sum)
for (int i=0; i < size; i++){
// do something that takes about 10seconds
sum++;
#pragma omp critical
cout << sum << " / " << size << endl;
}
这将返回如下内容:
1 / 100
1 / 100
2 / 100
1 / 100
...
但我想要这个:
1 / 100
2 / 100
3 / 100
。 ..
在sum
指令期间,有没有办法获得正确的reduction
值?
或者我应该使用其他方法?
答案 0 :(得分:0)
您应该使用其他方法。减少会创建一个线程私有变量(在您的情况下为sum
),当所有线程都加入时,它仅在结尾处减少。减少高度依赖于实现。它可以等待所有线程完成,它可以在线程完成时减少,它可以创建缩减树等等。
相反,要跟踪进度,您可以使用另一个变量numDone
,每个线程都会原子地增加。
修改强>
Wikipedia解释得非常好:
reduction(operator | intrinsic:list):变量具有本地副本 在每个线程中,但将汇总本地副本的值 (缩小)为全局共享变量。
答案 1 :(得分:0)
为了避免通信的需要(来自更新共享计数器),您可以打印出线程号以及它到目前为止处理的项目数,即
#pragma omp parallel
{
int count = 0;
#pragma omp for schedule(dynamic) // or whatever schedule you want
for(int i=0; i<size; ++i) {
// ...
printf("@ %d: done %d loops\n",
omp_get_thread_num(),++count); // should not need a critical section
}
}
在您的特定情况下,由于工作大约需要10秒,因此任何通信都不重要,但使用动态计划可能是值得的,特别是如果工作可能在不同的i
之间变化。
答案 2 :(得分:0)
reduction
子句具有非常明确的含义,详见latest OpenMP standard的2.9.3.6节。我怀疑你是否能够将它用于上述目的。
无论如何,只需对源进行一些修改即可实现该行为:
sum = 0
#pragma omp for shared(sum) schedule(guided)
for (int i=0; i < size; i++){
// do something that takes about 10seconds
#pragma omp critical(PRINT)
{
sum++;
cout << sum << " / " << size << endl;
}
}
通过这种方式,您可以确保一次只有一个线程尝试增加“总和”并在屏幕上打印。鉴于每次迭代花费的时间很长,这种同步不应该引起性能问题。