OpenMP中的数据处理子句
相关文档连接:
多核编程的几个难题及其应对策略(难题一)
private子句用于将一个或多个变量声明成线程私有的变量,变量声明成私有变量后,
指定每个线程都有它自己的变量私有副本,其他线程无法访问私有副本。即使在并行区域外有同名的共享变量,共享变量在并行区域内不起任何作用,并且并行区域内不会操作到外面的共享变量。
private子句的用法格式如下:
private(list)
int k = 100;
for ( k=0; k < 10; k++)
{
printf(
"k=%d/n",k);
}
printf(
"last k=%d/n",51); font-family:Arial; font-size:13.63636302947998px; line-height:25.99431800842285px">
上面程序执行后打印的结果如下:
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子句中。
先看一下以下的代码例子
for ( i=0; i < 4; i++)
k+=i;
上面代码执行后打印结果如下:
k=100
k=101
k=103
k=102
last k=100
@L_502_11@子句
有时在并行区域内的私有变量的值经过计算后,在退出并行区域时,需要将它的值赋给同名的共享变量,前面的private和firstprivate子句在退出并行区域时都没有将私有变量的最后取值赋给对应的共享变量,lastprivate子句就是用来实现在退出并行区域时将私有变量的值赋给共享变量。
举个例子如下:
上面代码执行后的打印结果如下:
last k=103
由于在并行区域内是多个线程并行执行的,最后到底是将那个线程的最终计算结果赋给了对应的共享变量呢?OpenMP规范中指出,如果是循环迭代,那么是将最后一次循环迭代中的值赋给对应的共享变量;如果是section构造,那么是最后一个section语句中的值赋给对应的共享变量。注意这里说的最后一个section是指程序语法上的最后一个,而不是实际运行时的最后一个运行完的。
如果是类(class)类型的变量使用在lastprivate参数中,那么使用时有些限制,需要一个可访问的,明确的缺省构造函数,除非变量也被使用作为firstprivate子句的参数;还需要一个拷贝赋值操作符,并且这个拷贝赋值操作符对于不同对象的操作顺序是未指定的,依赖于编译器的定义。
threadprivate子句用来指定全局的对象被各个线程各自复制了一个私有的拷贝,即各个线程具有各自私有的全局对象。
用法如下:
#pragma omp threadprivate(
list
)
new-line
int counter = 0;
#pragma omp threadprivate(counter)
int increment_counter()
{
counter++;
return(counter);
}
如果对于静态变量也同样可以使用threadprivate声明成线程私有的,上面的counter变量如改成用static类型来实现时,代码如下:
int increment_counter2()
static int counter = 0;
threadprivate和private的区别在于threadprivate声明的变量通常是全局范围内有效的,而private声明的变量只在它所属的并行构造中有效。
用作threadprivate的变量的地址不能是常数。
对于C++的类(class)类型变量,用作threadprivate的参数时有些限制,当定义时带有外部初始化时,必须具有明确的拷贝构造函数。
对于windows系统,threadprivate不能用于动态装载(使用LoadLibrary装载)的DLL中,可以用于静态装载的DLL中,关于windows系统中的更多限制,请参阅MSDN中有关threadprivate子句的帮助材料。
有关threadprivate命令的更多限制方面的信息,详情请参阅OpenMP2.5规范。
用法如下:
shared(
list
)
循环迭代变量在循环构造区域里是私有的。声明在循环构造区域内的自动变量都是私有的。
用法如下:
default(shared | none)
使用shared时,缺省情况下,传入并行区域内的同名变量被当作共享变量来处理,不会产生线程私有副本,除非使用private等子句来指定某些变量为私有的才会产生副本。
如果使用none作为参数,那么线程中用到的变量必须显示指定是共享的还是私有的,除了那些由明确定义的除外。
reduction(
operator
:
list
)
下表列出了可以用于reduction子句的一些操作符以及对应私有拷贝变量缺省的初始值,私有拷贝变量的实际初始值依赖于redtucion变量的数据类型。
表10-4-1:reduction操作中各种操作符号对应拷贝变量的缺省初始值
Operator
|
Initialization value
|
+
|
0
|
*
|
1
|
-
|
0
|
&
|
~0
|
|
|
0
|
^
|
0
|
&&
|
1
|
||
|
0
|
例如一个整数求和的程序如下:
int i,sum = 100;
for ( i = 0; i < 1000; i++ )
sum += i;
printf(
"sum = %ld/n",sum);
注意,如果在并行区域内不加锁保护就直接对共享变量进行写操作,存在数据竞争问题,会导致不可预测的异常结果。共享数据作为
private
、
firstprivate
、
lastprivate
、
threadprivate
、
reduction
子句的参数进入并行区域后,就变成线程私有了,不需要加锁保护了。
copyin子句用来将主线程中threadprivate变量的值拷贝到执行并行区域的各个线程的threadprivate变量中,便于线程可以访问主线程中的变量值,
copyin中的参数必须被声明成threadprivate的,对于类类型的变量,必须带有明确的拷贝赋值操作符。
int main(
int argc, char* argv[])
int iterator;
#pragma omp
section
{
int count1;
{
count1 = increment_counter();
}
printf(
"count1 = %ld/n",count1);
}
int count2;
count2 = increment_counter();
"count2 = %ld/n",count2);
printf(
"counter = %ld/n",counter);
打印结果如下:
count1 = 100
count2 = 200
counter = 0
从打印结果可以看出,两个线程都正确实现了各自的计数。
copyprivate
子句可以关联
single
构造,在
single
构造的
barrier
到达之前就完成了广播工作。
copyprivate
可以对
private
和
threadprivate
子句中的变量进行操作,但是当使用
single
构造时,
copyprivate
的变量不能用于
private
和
firstprivate
子句中。
#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,51); font-family:Arial; font-size:13.63636302947998px; line-height:25.99431800842285px; margin-left:21pt">
ThreadId: 3,51); font-family:Arial; font-size:13.63636302947998px; line-height:25.99431800842285px; margin-left:21pt">
ThreadId: 1,51); font-family:Arial; font-size:13.63636302947998px; line-height:25.99431800842285px; margin-left:21pt">
如果没有使用copyprivate子句,那么打印结果为:
从打印结果可以看出,使用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规范等参考文献,限于水平,可能存在对规范理解不足之处,请大家发现问题时不吝指正。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。