C++ Coder

HCP高性能计算架构,实现,编译器指令优化,算法优化, LLVM CLANG OpenCL CUDA OpenACC C++AMP OpenMP MPI

C++博客 首页 新随笔 联系 聚合 管理
  98 Posts :: 0 Stories :: 0 Comments :: 0 Trackbacks
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
}

 

image

图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
}



 

image

图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
}



 

image

图3、例3的执行结果

image

图4、例3中将copyin(sum)删除后的执行结果

通过以上图3、4可以看出copyin的用处是初始化各个线程中自己私有的sum变量。实际上定义sum为全局量时的初始值就是原sum值(如果不使用copyin的话)。

我想了想threadprivate和private以及firstprivate的区别。写出来大家讨论下。

1、threadprivate,限制变量为每个线程私有。被限制的变量必须具有全局特性,他的生命周期是整个程序。

2、private,可以限制变量为每个线程私有,但是他的生命周期是一次启动并行计算。

3、firstprivate,可以将穿行程序中的初值带进每个线程,变量为每个线程私有。生命周期与private相同。

4、还有个lastprivate的问题,他并不能在区域并行中使用。

大家实验把。。。

posted on 2012-10-21 11:55 jackdong 阅读(354) 评论(0)  编辑 收藏 引用 所属分类: OPenMP

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理