http://blog.csdn.net/bendanban/article/details/6303282
在上一节中我们讲的是一个常用的并行化编程方法(for的并行化),其实它只是并行化编程的一个特例,只是它的地位较高,或者说它比其它并行化更重要。在本节中我们将讨论一般的并行区域编程。
并行区域的编译指导语句一般格式
一般格式:#pragma omp parallel [clause[clause]…]{…}
其中{…}中为每个线程都执行的部分,在parallel后面可以跟随一些指导子句,例如:threadprivate、copyin等,本节中将以一些实例来依次讲解这些语句的作用。
时刻记住,主线程就是0号线程,这个与for不同,另外private、firstprivate、lastprivate是for并行的东西最好不要拿来比较,尽管我在本文里比较了,但是我还是感觉有些头痛啊。
例子实例
例1 不带指导子句的并行程序
#pragma omp parallel指示它下面的一对大括号内的程序复制执行threads个数次。默默人情况下,所有并行区域中的变量是共享的,所以一定要谨防数据竞争的发生。
#include
#include "omp.h"
int main(int argc, char* argv[])
{
#pragma omp parallel
for (int i = 0; i < 2; i++)
{
printf("Hello World! i = %d, Thread Num = %d/n", i, omp_get_thread_num());
}
return 0;
}
图1、例1的执行结果
例1的执行结果可以看出四个线程分别执行了一遍#pragma omp parallel下面的语句,想想一下如果使用#pragma omp parallel for会是什么样的结果。
例2 使用threadprivate子句
此命令表示所有并行线程使用指定变量为各自私有的,能被定义为各线程私有变量的变量只能是静态变量和全局变量。看下面的程序,希望你能发现,其实#pragma omp threadprivate()是可以单独使用的。
说明一下:被定义为threadprivate的变量对于每个线程永远是活的,你在任何时候再次重新启动各线程时,前面并行时最后得到的变量值仍然保留他的值,如果你用private代替threadprivate,那么你重新启动各线程时,变量的值仍然为0。如果你不初始化要声明为private的变量,那么在串行程序中,你就不能再没有任何赋值的情况下使用它,否则会引起异常的(VS2010)。而且private不能单独像threadprivate那样定义某个变量。
如果你使用另外#pragma omp threadprivate(var),那么var必须是静态变量或者全局变量,如过你在并行开始之前并没有初始化赋值,那么每个线程中默认var的值为0.如果你赋了初值,那么每个线程中var的初值都是你赋的初始值。其中主线程就是0号线程。如果你使用了#pragma omp private(var),那么var并不会赋初值,即使你在并行之前赋了初值。想想原先#pragma omp parallel for 的firstprivate就知道了,呵呵。在#pragma omp parallel中可以使用lastprivate,但是不能使用lastprivate,使用firstprivate(var)后,串行部分的var并不是并行时0号线程的var值,它仍未你原先赋的初值。是不是很绕啊?呵呵,你可以这样理解,使用firstprivate和private的并行都不是纯真的联合主线程的编号。这样就混不了了。
#include
#include "omp.h"
int sum = 0;
#pragma omp threadprivate(sum)
int main(int argc, char* argv[])
{
#pragma omp parallel
{
sum += omp_get_thread_num();
printf("parallel sum = %d; thread num = %d/n", sum, omp_get_thread_num());
}
printf("/nserial sum = %d; thread num = %d/n/n", sum, omp_get_thread_num());
#pragma omp parallel
printf("parallel sum = %d; thread num = %d/n", sum, omp_get_thread_num());
return 0;
}
图2、例2执行结果
threadprivate指定了sum这个变量属于每个线程,每个线程都有自己的sum变量,各个线程结束后他们的sum变量并没有注销,在此啊执行时,他们各自的sum值还保持原值。
例3 使用copyin
指定主线程的值拷贝到各线程中去,下面的例子中,sum是每个线程独有的,并且初始值都是0,main中第一行代码将0号线程的sum值赋为100,其它线程的sum值并没有变。
#include <stdio.h>
#include "omp.h"
int sum;
#pragma omp threadprivate(sum)
int main(int argc, char* argv[])
{
sum = 100;
#pragma omp parallel copyin(sum)
{
sum += omp_get_thread_num();
printf("parallel sum = %d; thread num = %d/n", sum, omp_get_thread_num());
}
printf("/nserial sum = %d; thread num = %d/n/n", sum, omp_get_thread_num());
#pragma omp parallel
printf("parallel sum = %d; thread num = %d/n", sum, omp_get_thread_num());
return 0;
}
图3、例3的执行结果
图4、例3中将copyin(sum)删除后的执行结果
通过以上图3、4可以看出copyin的用处是初始化各个线程中自己私有的sum变量。实际上定义sum为全局量时的初始值就是原sum值(如果不使用copyin的话)。
我想了想threadprivate和private以及firstprivate的区别。写出来大家讨论下。
1、threadprivate,限制变量为每个线程私有。被限制的变量必须具有全局特性,他的生命周期是整个程序。
2、private,可以限制变量为每个线程私有,但是他的生命周期是一次启动并行计算。
3、firstprivate,可以将穿行程序中的初值带进每个线程,变量为每个线程私有。生命周期与private相同。
4、还有个lastprivate的问题,他并不能在区域并行中使用。
大家实验把。。。