任务可以引用任务构造所在例程(主机例程)的堆栈中的数据。由于任务的执行可能会延迟到下一个隐式或显式屏障,所以任务有可能在主机例程的堆栈已经弹出,堆栈数据被覆盖(从而销毁任务引用的堆栈数据)之后执行。
确保插入所需的同步,以便当任务引用变量时,这些变量仍在堆栈中,如本节中的两个示例所示。
在Example 4–8 中,在 task 构造中将 i 指定为 shared,任务会访问在 work() 例程的堆栈中分配的 i 的副本。
任务的执行可能会延迟,使得任务将在 work() 例程已返回后,在 main() 中的并行区域末尾的隐式屏障处执行。那时,当任务引用 i 时,它会访问当时碰巧在堆栈中不确定的某个值。
为了获得正确的结果,请确保 work() 不在任务完成前返回。通过将 taskwait 指令插在 task 构造之后可以实现此目标,如Example 4–9 中所示。或者,可以在 task 构造中将 i 指定为 firstprivate 而不是 shared。
示例 4-8 堆栈数据:引用不正确#include <stdio.h>
#include <omp.h>
void work()
{
int i;
i = 10;
#pragma omp task shared(i)
{
#pragma omp critical
printf("In Task, i = %d\n",i);
}
}
int main(int argc, char** argv)
{
omp_set_num_threads(8);
omp_set_dynamic(0);
#pragma omp parallel
{
work();
}
}
示例 4-9 堆栈数据:引用正确
#include <stdio.h>
#include <omp.h>
void work()
{
int i;
i = 10;
#pragma omp task shared(i)
{
#pragma omp critical
printf("In Task, i = %d\n",i);
}
/* Use TASKWAIT for synchronization. */
#pragma omp taskwait
}
int main(int argc, char** argv)
{
omp_set_num_threads(8);
omp_set_dynamic(0);
#pragma omp parallel
{
work();
}
}
在以下示例中,task 构造中的 j 引用 sections 构造中的 j。因此,任务会访问 sections 构造中 j 的 firstprivate 副本,该副本在 Oracle Solaris Studio 中是 sections 构造的概要例程的堆栈中的局部变量。
任务的执行可能会延迟,使得任务将在 sections 构造的概要例程退出后,在 sections 区域末尾的隐式屏障处执行。因此当任务引用 j 时,会访问堆栈中的某个不确定的值。
为了得到正确的结果,请确保任务在 sections 区域达到其隐式屏障前执行,这可以通过在 task 构造之后插入 taskwait 指令来实现,如Example 4–11 中所示。或者,可以在 task 构造中将 j 指定为 firstprivate 而不是 shared。
示例 4-10 段数据:引用不正确#include <stdio.h>
#include <omp.h>
int main(int argc, char** argv)
{
omp_set_num_threads(2);
omp_set_dynamic(0);
int j=100;
#pragma omp parallel shared(j)
{
#pragma omp sections firstprivate(j)
{
#pragma omp section
{
#pragma omp task shared(j)
{
#pragma omp critical
printf("In Task, j = %d\n",j);
}
}
} /* Implicit barrier for sections */
} /* Implicit barrier for parallel */
printf("After parallel, j = %d\n",j);
}
示例 4-11 段数据:引用正确
#include <stdio.h>
#include <omp.h>
int main(int argc, char** argv)
{
omp_set_num_threads(2);
omp_set_dynamic(0);
int j=100;
#pragma omp parallel shared(j)
{
#pragma omp sections firstprivate(j)
{
#pragma omp section
{
#pragma omp task shared(j)
{
#pragma omp critical
printf("In Task, j = %d\n",j);
}
/* Use TASKWAIT for synchronization. */
#pragma omp taskwait
}
} /* Implicit barrier for sections */
}/* Implicit barrier for parallel */
printf("After parallel, j = %d\n",j);
}