您的位置:首页 > 编程语言

openMP编程探索3——并行区域编程

2011-04-05 19:57 239 查看
在上一节中我们讲的是一个常用的并行化编程方法(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的话)。

欢迎各位批评指正。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: