加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

openmp private之类的区分

(2018-01-08 12:56:49)
标签:

gpu

分类: 并行编程:GPU/MPI/OPEN***
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子句的参数;还需要一个拷贝赋值操作符,并且这个拷贝赋值操作符对于不同对象的操作顺序是未指定的,依赖于编译器的定义。
10.1.4 threadprivate子句(全局和静态变量
threadprivate子句用来指定全局的对象被各个线程各自复制了一个私有的拷贝,即各个线程具有各自私有的全局对象。在各个并行模块内每个线程私有且有效的,注意主线程的入出则不再有效
用法如下:
#pragma omp threadprivate(listnew-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声明的变量只在它所属的并行构造中有效。
http://s4/mw690/006TEzk1zy7hdqaJPSHc3&690private之类的区分" TITLE="openmp private之类的区分" />

threadprivate的对应只能用于copyin,copyprivate,schedule,num_threads和if子句中,不能用于任何其他子句中。
用作threadprivate的变量的地址不能是常数。
对于C++的类(class)类型变量,用作threadprivate的参数时有些限制,当定义时带有外部初始化时,必须具有明确的拷贝构造函数。
对于windows系统,threadprivate不能用于动态装载(使用LoadLibrary装载)的DLL中,可以用于静态装载的DLL中,关于windows系统中的更多限制,请参阅MSDN中有关threadprivate子句的帮助材料。
有关threadprivate命令的更多限制方面的信息,详情请参阅OpenMP2.5规范。
数据的Copy-in 和Copy-out:(threadprivate
      在并行化一个程序的时候,一般都必须考虑如何将私有变量的初值复制进来(Copy-in ),以初始化线程组中各个线程的私有副本。
在并行区的最后,还要将最后一次迭代/结构化块中计算出的私有变量复制出来(Copy-out),复制到主线程中的原始变量中。
copyprivate:使用一个私有变量将某一个值从一个成员线程广播到执行并行区的其他线程。该子句可以关联single结构(用于single指令中的指定变量为多个线程的共享变量),在所有的线程都离开该结构中的同步点之前,广播操作就已经完成。
shared子句用来声明一个或多个变量是共享变量。
用法如下:
shared(list)
需要注意的是,在并行区域内使用共享变量时,如果存在写操作,必须对共享变量加以保护,否则不要轻易使用共享变量,尽量将共享变量的访问转化为私有变量的访问。
循环迭代变量在循环构造区域里是私有的。声明在循环构造区域内的自动变量都是私有的。
default子句用来允许用户控制并行区域中变量的共享属性。
用法如下:
default(shared none)
使用shared时,缺省情况下,传入并行区域内的同名变量被当作共享变量来处理,不会产生线程私有副本,除非使用private等子句来指定某些变量为私有的才会产生副本。
如果使用none作为参数,那么线程中用到的变量必须显示指定是共享的还是私有的,除了那些由明确定义的除外。

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构造内的赋值。

0

阅读 收藏 喜欢 打印举报/Report
前一篇:Linux常见指令
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有