我发现虽然这个 C 代码提供了一个有序的整数列表(正如预期的那样):
#include <stdio.h>
#include <unistd.h>
#include <omp.h>
int main() {
#pragma omp parallel for ordered schedule(dynamic)
for (int i=0; i<10; i++) {
#pragma omp ordered
{
printf("%i (tid=%i)\n",i,omp_get_thread_num(); fflush(stdout);
}
}
}
同时使用gcc和icc,以下内容会产生不良行为:
#include <stdio.h>
#include <unistd.h>
#include <omp.h>
int main() {
#pragma omp parallel for ordered schedule(dynamic)
for (int i=0; i<10; i++) {
#pragma omp ordered
{
printf("%i (tid=%i)\n",i,omp_get_thread_num()); fflush(stdout);
}
usleep(100*omp_get_thread_num());
printf("WORK IS DONE (tid=%i)\n",omp_get_thread_num()); fflush(stdout);
usleep(100*omp_get_thread_num());
#pragma omp ordered
{
printf(" %i (tid=%i)\n",i,omp_get_thread_num()); fflush(stdout);
}
}
}
我喜欢看到的是:
0
1
2
3
4
5
6
7
8
9
工作完成了
工作完成了
工作完成了
工作完成了
工作完成了
工作完成了
工作完成了
工作完成了
工作完成了
工作完成了
0
1
2
3
4
5
6
7
8
9
但是用gcc得到:
0(tid = 5)
工作完成(tid = 5)
0(tid = 5)
1(tid = 2)
工作完成(tid = 2)
1(tid = 2)
2(tid = 0)
工作完成(tid = 0)
2(tid = 0)
3(tid = 6)
工作完成(tid = 6)
3(tid = 6)
4(tid = 7)
工作完成(tid = 7)
4(tid = 7)
5(tid = 3)
工作完成(tid = 3)
5(tid = 3)
6(tid = 4)
工作完成(tid = 4)
6(tid = 4)
7(tid = 1)
工作完成(tid = 1)
7(tid = 1)
8(tid = 5)
工作完成(tid = 5)
8(tid = 5)
9(tid = 2)
工作完成(tid = 2)
9(tid = 2)
(所以一切都得到了订购 - 甚至是可并行化的工作部分)
用icc:
1(tid = 0)
2(tid = 5)
3(tid = 1)
4(tid = 2)
工作完成(tid = 1)
工作完成(tid = 3)
3(tid = 1)
6(tid = 4)
7(tid = 7)
8(tid = 1)
工作完成(tid = 0)
5(tid = 6)
工作完成(tid = 2)
1(tid = 0)
9(tid = 0)
工作完成(tid = 0)
工作完成(tid = 5)
工作完成(tid = 1)
9(tid = 0)
0(tid = 3)
8(tid = 1)
工作完成(tid = 4)
工作完成(tid = 6)
2(tid = 5)
工作完成(tid = 7)
6(tid = 4)
5(tid = 6)
4(tid = 2)
7(tid = 7)
(所以没有任何东西得到订购甚至没有订购的条款)
在一个有序循环未定义的行为中使用多个有序子句或者在这里发生了什么?在我能找到的任何OpenMP文档中,我无法找到任何禁止每个循环的多个子句的内容。
我知道在这个简单的例子中我可以像
一样分开循环int main() {
for (int i=0; i<10; i++) {
printf("%i (tid=%i)\n",i,omp_get_thread_num()); fflush(stdout);
}
#pragma omp parallel for schedule(dynamic)
for (int i=0; i<10; i++) {
usleep(100*omp_get_thread_num());
printf("WORK IS DONE (tid=%i)\n",omp_get_thread_num()); fflush(stdout);
usleep(100*omp_get_thread_num());
}
for (int i=0; i<10; i++) {
printf(" %i (tid=%i)\n",i,omp_get_thread_num()); fflush(stdout);
}
}
所以我没有找到解决方法。我真的很想了解这里发生了什么,这样我就可以处理真实的情况而不会遇到任何破坏性/意外的事情。
我真的希望你能帮助我。
答案 0 :(得分:1)
根据OpenMP 4.0 API specifications你不能。
循环指令中只能出现一个有序子句(第58页)
答案 1 :(得分:0)
我在并行编程方面有点新,但我会尽力帮助你。
我修改了你的代码并对其进行了测试:
#include <stdio.h>
#include <unistd.h>
#include <omp.h>
int main() {
#pragma omp parallel num_threads(8)
{
#pragma omp for ordered schedule(dynamic)
for (int i=0; i<10; i++) {
#pragma omp ordered
printf("%i (tid=%i) \n",i,omp_get_thread_num()); fflush(stdout);
}
printf("WORK IS DONE (tid=%i)\n",omp_get_thread_num()); fflush(stdout);
}
}
调整用于编译示例的机器的线程数。代码中的问题是对printf的访问表明工作已经完成,每个线程将独立执行此部分。在我的例子中,我让for循环的迭代按照ordered子句的状态执行,然后for&#39; s子句隐式屏障让每个线程都等待,直到所有线程都在for之后就到达了代码的位置。循环和for子句,然后每个打印出&#34;工作完成&#34;。如果您没有使用for子句并且想要获得相同的输出,则可以使用显式屏障,或者使用#pragma omp barrier。
注意:&#34; pragma omp parallel&#34;也使用隐式屏障,之后已经创建的每个线程都被销毁
这是我获得的可能输出:
0 (tid=7)
1 (tid=5)
2 (tid=0)
3 (tid=4)
4 (tid=1)
5 (tid=3)
6 (tid=2)
7 (tid=7)
8 (tid=5)
9 (tid=0)
WORK IS DONE (tid=5)
WORK IS DONE (tid=2)
WORK IS DONE (tid=1)
WORK IS DONE (tid=4)
WORK IS DONE (tid=0)
WORK IS DONE (tid=7)
WORK IS DONE (tid=3)
WORK IS DONE (tid=6)
如果这是您希望看到的那种输出,这是实现它的一种可能方式。希望这会有所帮助,如有必要,请随时寻求进一步的帮助。继续编码!