周伟明的专栏

<<软件测试实践>> 已上市

周伟明ID:drzhouweiming
183236次访问,排名365好友1人,关注者10
软件技术爱好及研究者
drzhouweiming的文章
原创 48 篇
翻译 0 篇
转载 0 篇
评论 314 篇
周伟明的公告
一书已上市, 欢迎大家提出意见!
最近评论
drzhouweiming:因为sections语句后面有隐含的barrier
如果要将其变成并行的话,需要使用nowait子句
kuangxiangjie:这种方式和前面那种方式的区别是,两个sections语句是串行执行的,即第二个sections语句里的代码要等第一个sections语句里的代码执行完后才能执行。

您好,我对这句话不是很明白....parallel不是并行的么,怎么在它里面的两个ses会是串行的呢
algcfx:Wow gold
dimire:LZ你好,我参考你的第一个测试程序int main(int argc, char* argv[])
{
#pragma omp parallel for
for (int i = 0; i < 10; i++ )
{
printf("i = %d\n", i);
}
……
dimire:学习了
文章分类
    收藏
      相册
      最近文章
      1、多核新观念-象使用内存一样使用CPU?
      2、多核编程中的任务随机竞争模式的概率分析
      3、OpenMP创建线程中的锁及原子操作性能比较
      4、多核编程中的任务分组竞争模式
      5、称球问题的测试解法
      90%程序员写不出无BUG的二分查找程序?
      C/C++代码检视实例
      多核编程中的负载平衡难题
      多核编程中的锁竞争难题
      微软过桥问题与测试人员素养
      接口关系稳定原理探索
      接口设计定理
      模块分解原理与三权分立
      模块分解原理的探索
      测试驱动需求分析
      筑一座坝治好中国的沙漠
      存档
      软件项目交易
      订阅我的博客
      XML聚合  FeedSky
      订阅到鲜果
      订阅到Google
      订阅到抓虾
      订阅到BlogLines
      订阅到Yahoo
      订阅到GouGou
      订阅到飞鸽
      订阅到Rojo
      订阅到newsgator
      订阅到netvibes

      原创 OpenMP中的数据处理子句收藏

      新一篇: 高房价与多核分布式计算 | 旧一篇: SD2.0大会的一些随想

       
      OpenMP中的数据处理子句
      相关文档连接:
      多核编程的几个难题及其应对策略(难题一)
      private子句用于将一个或多个变量声明成线程私有的变量,变量声明成私有变量后,指定每个线程都有它自己的变量私有副本,其他线程无法访问私有副本。即使在并行区域外有同名的共享变量,共享变量在并行区域内不起任何作用,并且并行区域内不会操作到外面的共享变量。
      private子句的用法格式如下:
      private(list)
      下面便是一个使用private子句的代码例子:
               int k = 100;
      #pragma omp parallel for private(k)
               for ( k=0; k < 10; k++)
               {
                         printf("k=%d\n", k);
               }
       
               printf("last k=%d\n", k);
      上面程序执行后打印的结果如下:
      k=6
      k=7
      k=8
      k=9
      k=0
      k=1
      k=2
      k=3
      k=4
      k=5
      last k=100
      从打印结果可以看出,for循环前的变量k和循环区域内的变量k其实是两个不同的变量。
      用private子句声明的私有变量的初始值在并行区域的入口处是未定义的,它并不会继承同名共享变量的值。
      出现在reduction子句中的参数不能出现在private子句中。
      private声明的私有变量不能继承同名变量的值,但实际情况中有时需要继承原有共享变量的值,OpenMP提供了firstprivate子句来实现这个功能。
      先看一下以下的代码例子
               int k = 100;
      #pragma omp parallel for firstprivate(k)
               for ( i=0; i < 4; i++)
               {
                         k+=i;
                         printf("k=%d\n",k);
               }
       
               printf("last k=%d\n", k);
       
      上面代码执行后打印结果如下:
      k=100
      k=101
      k=103
      k=102
      last k=100
       
      从打印结果可以看出,并行区域内的私有变量k继承了外面共享变量k的值100作为初始值,并且在退出并行区域后,共享变量k的值保持为100未变。
      有时在并行区域内的私有变量的值经过计算后,在退出并行区域时,需要将它的值赋给同名的共享变量,前面的private和firstprivate子句在退出并行区域时都没有将私有变量的最后取值赋给对应的共享变量,lastprivate子句就是用来实现在退出并行区域时将私有变量的值赋给共享变量。
      举个例子如下:
               int k = 100;
      #pragma omp parallel for firstprivate(k),lastprivate(k)
               for ( i=0; i < 4; i++)
               {
                         k+=i;
                         printf("k=%d\n",k);
               }
               printf("last k=%d\n", k);
      上面代码执行后的打印结果如下:
      k=100
      k=101
      k=103
      k=102
      last k=103
      从打印结果可以看出,退出for循环的并行区域后,共享变量k的值变成了103,而不是保持原来的100不变。
      由于在并行区域内是多个线程并行执行的,最后到底是将那个线程的最终计算结果赋给了对应的共享变量呢?OpenMP规范中指出,如果是循环迭代,那么是将最后一次循环迭代中的值赋给对应的共享变量;如果是section构造,那么是最后一个section语句中的值赋给对应的共享变量。注意这里说的最后一个section是指程序语法上的最后一个,而不是实际运行时的最后一个运行完的。
      如果是类(class)类型的变量使用在lastprivate参数中,那么使用时有些限制,需要一个可访问的,明确的缺省构造函数,除非变量也被使用作为firstprivate子句的参数;还需要一个拷贝赋值操作符,并且这个拷贝赋值操作符对于不同对象的操作顺序是未指定的,依赖于编译器的定义。
      threadprivate子句用来指定全局的对象被各个线程各自复制了一个私有的拷贝,即各个线程具有各自私有的全局对象。
      用法如下:
      #pragma omp threadprivate(list) new-line
      下面用threadprivate命令来实现一个各个线程私有的计数器,各个线程使用同一个函数来实现自己的计数。计数器代码如下:
      int counter = 0;
      #pragma omp threadprivate(counter)
      int increment_counter()
      {
               counter++;
               return(counter);
      }
      如果对于静态变量也同样可以使用threadprivate声明成线程私有的,上面的counter变量如改成用static类型来实现时,代码如下:
      int increment_counter2()
      {
      static int counter = 0;
      #pragma omp threadprivate(counter)
               counter++;
               return(counter);
      }
       
       
      threadprivate和private的区别在于threadprivate声明的变量通常是全局范围内有效的,而private声明的变量只在它所属的并行构造中有效。
      threadprivate的对应只能用于copyin,copyprivate,schedule,num_threads和if子句中,不能用于任何其他子句中。
      用作threadprivate的变量的地址不能是常数。
      对于C++的类(class)类型变量,用作threadprivate的参数时有些限制,当定义时带有外部初始化时,必须具有明确的拷贝构造函数。
      对于windows系统,threadprivate不能用于动态装载(使用LoadLibrary装载)的DLL中,可以用于静态装载的DLL中,关于windows系统中的更多限制,请参阅MSDN中有关threadprivate子句的帮助材料。
      有关threadprivate命令的更多限制方面的信息,详情请参阅OpenMP2.5规范。
      shared子句用来声明一个或多个变量是共享变量。
      用法如下:
      shared(list)
      需要注意的是,在并行区域内使用共享变量时,如果存在写操作,必须对共享变量加以保护,否则不要轻易使用共享变量,尽量将共享变量的访问转化为私有变量的访问。
      循环迭代变量在循环构造区域里是私有的。声明在循环构造区域内的自动变量都是私有的。
      default子句用来允许用户控制并行区域中变量的共享属性。
      用法如下:
      default(shared | none)
      使用shared时,缺省情况下,传入并行区域内的同名变量被当作共享变量来处理,不会产生线程私有副本,除非使用private等子句来指定某些变量为私有的才会产生副本。
      如果使用none作为参数,那么线程中用到的变量必须显示指定是共享的还是私有的,除了那些由明确定义的除外。
      reduction子句主要用来对一个或多个参数条目指定一个操作符,每个线程将创建参数条目的一个私有拷贝,在区域的结束处,将用私有拷贝的值通过指定的运行符运算,原始的参数条目被运算结果的值更新。
       
      reduction子句用法如下:
      reduction(operator:list)
      下表列出了可以用于reduction子句的一些操作符以及对应私有拷贝变量缺省的初始值,私有拷贝变量的实际初始值依赖于redtucion变量的数据类型。
      表10-4-1:reduction操作中各种操作符号对应拷贝变量的缺省初始值
      Operator
      Initialization value
      +
      0
      *
      1
      -
      0
      &
      ~0
      |
      0
      ^
      0
      &&
      1
      ||
      0
       
      例如一个整数求和的程序如下:
      int i, sum = 100;
       
      #pragma omp parallel for reduction(+: sum)
      for ( i = 0; i < 1000; i++ )
      {
       sum += i;
      }
       
      printf( "sum = %ld\n", sum);
       
      注意,如果在并行区域内不加锁保护就直接对共享变量进行写操作,存在数据竞争问题,会导致不可预测的异常结果。共享数据作为privatefirstprivatelastprivatethreadprivatereduction子句的参数进入并行区域后,就变成线程私有了,不需要加锁保护了。
      copyin子句用来将主线程中threadprivate变量的值拷贝到执行并行区域的各个线程的threadprivate变量中,便于线程可以访问主线程中的变量值,
      用法如下:
      copyin(list)
       
      copyin中的参数必须被声明成threadprivate的,对于类类型的变量,必须带有明确的拷贝赋值操作符。
      对于前面threadprivate中讲过的计数器函数,如果多个线程使用时,各个线程都需要对全局变量counter的副本进行初始化,可以使用copyin子句来实现,示例代码如下:
      int main(int argc, char* argv[])
      {
               int iterator;
      #pragma omp parallel sections copyin(counter)
               {
      #pragma omp section
                         {
                                  int count1;
                                  for ( iterator = 0; iterator < 100; iterator++ )
                                  {
                                           count1 = increment_counter();
                                  }
                                  printf("count1 = %ld\n", count1);
                         }
      #pragma omp section
                         {
                                  int count2;
                                  for ( iterator = 0; iterator < 200; iterator++ )
                                  {
                                           count2 = increment_counter();
                                  }
                                  printf("count2 = %ld\n", count2);
                         }
               }
               printf("counter = %ld\n", counter);
      }
      打印结果如下:
      count1 = 100
      count2 = 200
      counter = 0
       
      从打印结果可以看出,两个线程都正确实现了各自的计数。
      copyprivate子句提供了一种机制用一个私有变量将一个值从一个线程广播到执行同一并行区域的其他线程。
      用法如下:
      copyprivate(list)
      copyprivate子句可以关联single构造,在single构造的barrier到达之前就完成了广播工作。copyprivate可以对privatethreadprivate子句中的变量进行操作,但是当使用single构造时,copyprivate的变量不能用于privatefirstprivate子句中。
       
      下面便是一个使用copyprivate的代码例子:
      int counter = 0;
      #pragma omp threadprivate(counter)
      int increment_counter()
      {
               counter++;
               return(counter);
      }
      #pragma omp parallel
               {
                         int    count;
      #pragma omp single copyprivate(counter)
                         {
                                  counter = 50;
                         }
                         count = increment_counter();
                         printf("ThreadId: %ld, count = %ld\n", omp_get_thread_num(), count);
      }
      打印结果为:
      ThreadId: 2, count = 51
      ThreadId: 0, count = 51
      ThreadId: 3, count = 51
      ThreadId: 1, count = 51
       
      如果没有使用copyprivate子句,那么打印结果为:
      ThreadId: 2, count = 1
      ThreadId: 1, count = 1
      ThreadId: 0, count = 51
      ThreadId: 3, count = 1
       
      从打印结果可以看出,使用copyprivate子句后,single构造内给counter赋的值被广播到了其他线程里,但没有使用copyprivate子句时,只有一个线程获得了single构造内的赋值,其他线程没有获取single构造内的赋值。
         参考文献:

      Ananth Grama, Anshul Gupta,“并行计算导论”,张武等译,机械工业出版社,2005.01

      Michael J. Quinn, “MPI与OpenMP并行程序设计”,陈文光等译,清华大学出版社,2004.10

      Shameem Akhter等,“多核程序设计技术-通过软件多线程提升性能”,电子工业出版社,2007.03
      OpenMP2.5规范     http://www.openmp.org/
      OpenMP2.0规范     http://www.openmp.org/
      MSDN帮助材料           ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.VisualStudio.v80.chs/dv_vclang/html/652414c5-78ed-4b7f-8283-1a9fe4c5e78d.htm  
      注:本文的写作主要参考OpenMP2.5规范等参考文献,限于水平,可能存在对规范理解不足之处,请大家发现问题时不吝指正。

      发表于 @ 2008年01月10日 11:02:00|评论(loading...)|编辑

      新一篇: 高房价与多核分布式计算 | 旧一篇: SD2.0大会的一些随想

      评论:没有评论。

      发表评论  


      当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
      Csdn Blog version 3.1a
      Copyright © 周伟明