#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
void para_print()
{
//automatic vars in a routine called within an omp region is private implicitly
int i,tid;
/*if you need shared vars inside omp function call, use static vars;
* the side effect is static vars keeps its previous value
* if not reset a initial value during each call*/
static int j;
#pragma omp single
{
printf("tid: i,j\n");
j=10;
}
#pragma omp for
for(i=0;i<5;i++)
{
tid=omp_get_thread_num();
#pragma omp critical
{
j++;
printf("%d: %d,%d\n",tid,i,j);
}
}
}
int main()
{
int i;
#pragma omp parallel num_threads(5)
{
para_print(); //注意此时有内嵌omp for,所以不是线程重复执行,要把omp for放进去分析
para_print();
}
return 0;
}
运行结果:
结论:
1. 可以在omp parallel并行域所调用的函数中再进行并行任务分配(即在子函数中加入omp single, omp for等等构造),效果等同于将子函数的代码嵌入到主函数中做并行。
注意:若在parallel并行域所调用的子函数中再次出现omp parallel并行域,则属于嵌套并行(nested parallelization),默认情况下,内层并行域无效(即被作为串行代码执行),除非在嵌套并行域之前调用了omp_set_nest(1)或者设置环境变量OMP_NESTED=true以启用嵌套。
而parallel并行域内出现omp for, omp task等构造(construct)并非嵌套并行,因为construct不产生新的线程组,但并行域会产生新的线程组。
2 并行域内在子函数中定义的自动局部变量为私有变量(private),子函数的形参继承实参的数据属性,子函数的静态变量为共享变量。比如以上程序中将j声明为静态变量以便使其成为共享变量(shared)。在该子函数的并行结构中再附加shared语句是违法的。
若没有将j声明为静态(将上面代码中static int j改为int j),则运行结果为:
tid: i,j
1: 1,1
0: 0,11
2: 2,1
4: 4,1
3: 3,1
tid: i,j
0: 0,11
4: 4,1
2: 2,1
1: 1,1
3: 3,1
可见此时j为私有变量,只有0号线程执行了single部分,其它线程中j的初值默认为0.以上是原贴http://asc.2dark.org/node/98,的运行结果,我的运行结果有误,提示j没有被初始化.总之,如果没有static,此时j将只作为私有变量,只有0号线程中的j有值.
注意:使用静态变量使子函数变量共享化的一个负面效果是如果不做初始化则静态变量会保留上次调用后的值。比如如果把上面代码中的j=10语句删除(记得保留静态属性static int j),则运行结果如下:
tid: i,j
0: 0,1
3: 3,2
1: 1,3
4: 4,4
2: 2,5
tid: i,j
0: 0,6
2: 2,7
1: 1,8
3: 3,9
4: 4,10
可见第二次调用para_print时j保留了上次调用时的值j=5作为第二次调用的初值。
关于变量作用域的更完整规则参见openmp specification中的sharing attribute rules章节。在这里下载openmp官方标准:
http://openmp.org/wp/openmp-specifications/