我不熟悉在OpenMP中使用task
子句,我不确定我是否正确理解了它的含义。这是我的测试代码:
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
void task(int p)
{
printf("Thread ID: %d, task: %d\n", omp_get_thread_num(), p);
}
#define N 5
int main(int argc, char* argv[])
{
int i;
#pragma omp parallel num_threads(3)
{
#pragma omp single
{
for(i = 0;i < N; i++)
{
#pragma omp task
task(i);
}
}
}
return 0;
}
我使用Intel 16.0编译器编译我的代码,并希望获得如下输出:
- Thread ID: 0, task: 0
- Thread ID: 2, task: 4
- Thread ID: 2, task: 3
- Thread ID: 0, task: 1
- Thread ID: 1, task: 2
但是,此代码的实际输出是:
- Thread ID: 0, task: 5
- Thread ID: 2, task: 5
- Thread ID: 2, task: 5
- Thread ID: 0, task: 5
- Thread ID: 1, task: 5
&#39;任务的输出:&#39;固定为5而不是0到4,这不是我预期的。任何人都可以帮我理解这个结果吗?
答案 0 :(得分:0)
问题与任务构造中i
的隐式数据共享有关。
如果我没记错的话,i
被确定为在任务构造中共享,因为这个变量被隐含地确定为在并行中共享,但也许我错了。假设我是对的,您的代码会生成竞争条件,因为任务正在捕获&i
而不是i
的值。请注意,执行任务后i
会按值传递(i
的值可能为5)。
我的建议:如果您不确定变量的隐式数据共享,请将其始终显式化。在您的情况下,使用firstprivate(i)
答案 1 :(得分:0)
您观察到的问题是由于可见性的变化。我在为gcc 4.8.4和icc 16.0.3编译它时重新运行了你的应用程序,我得到了以下结果(因执行而异):
<强> GCC 强>
Thread ID: 2, task: 1
Thread ID: 2, task: 5
Thread ID: 2, task: 5
Thread ID: 1, task: 5
Thread ID: 0, task: 2
<强> ICC 强>
Thread ID: 0, task: 5
Thread ID: 1, task: 3
Thread ID: 1, task: 5
Thread ID: 0, task: 5
Thread ID: 2, task: 5
由于变量i
的可见性未在#pragma omp
构造中声明,因此编译器决定i
应声明为shared
,这意味着任何线程完成的修改被其余的线程观察到。
在您的情况下,由于您希望打印的消息显示任务0到4,这意味着每个线程都应该有private
i
副本,如下面的代码所示 - 它源于你的。请注意#pragma omp parallel
:
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
void task(int p)
{
printf("Thread ID: %d, task: %d\n", omp_get_thread_num(), p);
}
#define N 5
int main(int argc, char* argv[])
{
int i;
#pragma omp parallel num_threads(3) private(i)
{
#pragma omp single
{
for(i = 0;i < N; i++)
{
#pragma omp task
task(i);
}
}
}
return 0;
}
无论您使用何种编译器,此版本的结果为:
Thread ID: 2, task: 1
Thread ID: 2, task: 3
Thread ID: 2, task: 4
Thread ID: 1, task: 0
Thread ID: 0, task: 2
注意 private
的展示位置可以进入#pragma omp parallel
构造,或者如用户smateo建议的那样,它可以进入#pragma omp task
(但是在后一种情况下,firstprivate
在进入task
构造时保持变量的值。关于它去向的实际决定取决于你的应用程序的语义。