Multithreading 使用task子句时,我的OpenMP代码中会出现混乱的结果
我对在OpenMP中使用Multithreading 使用task子句时,我的OpenMP代码中会出现混乱的结果,multithreading,task,openmp,Multithreading,Task,Openmp,我对在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
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;
}
但是,此代码的实际输出是:
- 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
“task:”的输出固定为5,而不是0到4,这不是我所期望的。有人能帮我理解这个结果吗?这个问题与任务结构中
i
的隐式数据共享有关
如果我回忆正确,I
被确定为在任务构造中共享,因为这个变量被隐式地确定为在并行中共享,但可能我错了。假设我是对的,您的代码会生成竞争条件,因为任务捕获的是&I
,而不是I
的值。请注意,i
在任务执行后按值传递(并且i
的值可能为5)
我的建议:如果您不确定变量的隐式数据共享,请始终明确。在您的情况下,使用
firstprivate(i)
注释任务。问题与任务构造中i
的隐式数据共享有关
如果我回忆正确,I
被确定为在任务构造中共享,因为这个变量被隐式地确定为在并行中共享,但可能我错了。假设我是对的,您的代码会生成竞争条件,因为任务捕获的是&I
,而不是I
的值。请注意,i
在任务执行后按值传递(并且i
的值可能为5)
我的建议:如果您不确定变量的隐式数据共享,请始终明确。在您的情况下,请使用
firstprivate(i)
注释任务。您观察到的问题是由于可见度可变。在为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
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
icc
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
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
声明为共享
,这意味着任何线程所做的修改都会被剩余线程观察到
在您的例子中,由于您希望打印显示任务0到4的消息,这意味着每个线程都应该有其i
的private
副本,如下代码所示——这是您的代码派生的。请注意#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;
}
请注意,
private
的位置可以进入#pragma omp parallel
结构,或者按照用户smateo的建议,它可以进入#pragma omp task
(但在后一种情况下,作为firstprivate
以在进入task
结构时保留变量的值)。实际的决定取决于应用程序的语义。您观察到的问题是由于可变的可见性。在为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
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
icc
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
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
声明为共享
,这意味着任何线程所做的修改都会被剩余线程观察到
在您的例子中,由于您希望打印显示任务0到4的消息,这意味着每个线程都应该有其i
的private
副本,如下代码所示——这是您的代码派生的。请注意#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;
}
请注意,
private
的位置可以进入#pragma omp parallel
结构,或者按照用户smateo的建议,它可以进入#pragma omp task
(但在后一种情况下,作为firstprivate
以在进入task
结构时保留变量的值)。具体的决定取决于应用程序的语义。我也尝试过gcc 4.4.7编译器,结果与英特尔编译器相似。我也尝试过gcc 4.4.7编译器,结果与英特尔编译器相似。我建议您接受/支持我们的任何答案?那么,我可以建议你接受/赞成我们的任何回答吗?