OpenMP数据处理子句
1.private子句
该子句用于将一个或多个变量声明成线程私有的变量,变量声明成私有变量后,指定每个线程都有它自己的变量私有副本,其他线程无法访问私有副本,即使在并行块之外有同名的共享变量,该共享变量在并行区域内也不起效果,且并行区域内不会操作到外面的共享变量。
private子句的用法格式:
private(list)
举例代码:
//正常for循环代码:
#include<omp.h>
#include<iostream>
using namespace std;
int main()
{
int k = 100;
cout << "the first k is:"<<k<<" the address is:" << &k << endl;
for (k = 0; k < 10; k++)
{
cout << "k is:" << k << " the adddress of k is:"<<&k<< endl;
}
cout << "the last k is:" << k <<" the address is: "<<&k<< endl;
return 0;
}
加上private子句之后:
//添加private子句的并行循环代码:
#include<omp.h>
#include<iostream>
using namespace std;
int main()
{
int k = 100;
cout << "the first k is:"<<k<<" the address is:" << &k << endl;
#pragma omp parallel for private(k) //private子句
for (k = 0; k < 10; k++)
{
cout << "k is:" << k << " the adddress of k is:"<<&k<< endl;
}
cout << "the last k is:" << k <<" the address is: "<<&k<< endl;
return 0;
}
输出为:
可以看到:在没有private子句的代码输出中,最后的变量k值并非最初始的值,是相同地址存储值在不停被修改;而含private子句的代码中,并行块使用新的地址存储变量私有副本,并且在并行块结束后,副本值并未影响到并行块外面的共享变量k值。
2.firstprivate 子句
private声明的私有变量不能集成同名变量的值,但实际情况中有时候需要继承原有共享变量的值,openMP提供firstprivate子句来实现。
代码:
#include<omp.h>
#include<iostream>
using namespace std;
int main()
{
int k = 100;
cout << "the first k is:"<<k<<" the address is:" << &k << endl;
#pragma omp parallel for firstprivate(k) //firstprivate声明私有变量k并继承共享变量的值,100.
for (int i = 0; i < 10; i++)
{
k = k + i;
cout << "k is:" << k << " the adddress of k is:"<<&k<< endl;
}
cout << "the last k is:" << k <<" the address is: "<<&k<< endl;
return 0;
}
输出为:
并行区域内私有变量k继承了共享变量k的100作为初始值,进行运算。但在退出并行区域后,共享变量值保持为100未变。
3.lastprivate子句
在并行区域内的私有变量值经过计算后,有时候在退出并行区域后,希望将它的值赋给同名的共享变量。这时候使用lastprivate.
代码:
#include<omp.h>
#include<iostream>
using namespace std;
int main()
{
int k = 100;
cout << "the first k is:"<<k<<" the address is:" << &k << endl;
#pragma omp parallel for firstprivate(k),lastprivate(k) //先从共享变量继承,后传出并行块赋值给共享变量
for (int i = 0; i < 10; i++)
{
k = k + i;
cout << "k is:" << k << " the adddress of k is:"<<&k<< endl;
}
cout << "the last k is:" << k <<" the address is: "<<&k<< endl;
return 0;
}
输出为:
注:并行区域内多线程并行执行,如果是循环迭代,那么是将最后一次循环迭代中的值赋给对应的共享变量;如果是section构造,那么是语法程序上的最后一个(非实际运行时最后运行完的一个)section语句的值赋给对应的共享变量。
如果是类(class)类型的变量使用在lastprivate参数中,那么使用时有些限制,需要一个可访问的,明确的缺省构造函数,除非变量也被使用作为firstprivate子句的参数;还需要一个拷贝赋值操作符,并且这个拷贝赋值操作符对于不同对象的操作顺序是未指定的,依赖于编译器的定义。
4.threadprivate子句
用来指定全局的对象被各个线程各自赋值了一个私有的拷贝,即各个线程具有各自私有的全局对象。
用法如下:
#pragma omp threadprivate(list) new-line
5.shared子句
shared 子句用来声明一个或多个变量是共享变量
用法:
shared(list)
6.default子句
用来允许用户控制并行区域中变量的共享属性
用法:
default(shared|none)
7.reduction 子句
代码:
#include<omp.h>
#include<iostream>
using namespace std;
//reduction 子句主要用于对一个或者多个参数条目指定操作符,每个线程将创建参数条目的一个私有拷贝
//在区域结束处,将用私有拷贝的值通过指定的运算符运算,原始的参数条目被运算结果的值更新
int main()
{
int i, sum = 100;
int num_thread = 0;
#pragma omp parallel for reduction(+:sum),lastprivate(num_thread),num_threads(4) //指定四个线程执行并行代码块
for (i = 0; i < 1000; i++)
{
sum += i;
num_thread= omp_get_num_threads();
}
cout << num_thread << endl;
cout << sum << endl;
return 0;
}
//如果在并行区域内不加锁保护就直接对共享变量进行写操作,会存在数据竞争问题,导致异常结果。
//共享数据作为private/firstprivate/lastprivate/threadprivate/reduction 子句的参数进入并行区域后,变成程线程私有了,不需要加锁保护
8.copyin子句
代码:
#include<omp.h>
#include<iostream>
using namespace std;
//copyin子句用来将主线程中threadprivate变量的值拷贝到执行
//并行区域的各个线程的threadprivate变量中,便于线程可以访问主线程中的变量值
//用法:copyin(list)
//copyin中的参数必须声明成threadprivate.
int counter = 0; //计数器
#pragma omp threadprivate(counter) //声明为threadprivate
int in_counter()
{
counter++;
return(counter);
}
int main()
{
int iterator;
#pragma omp parallel sections copyin(counter) //copyin 针对的是声明为threadprivate的变量
{
#pragma omp section
{
int count1;
for (iterator = 0; iterator < 100; iterator++)
{
count1 = in_counter();
}
cout << "count1: " << count1 << endl;
}
#pragma omp section
{
int count2;
for (iterator = 0; iterator < 200; iterator++)
{
count2 = in_counter();
}
cout << "count2: " << count2 << endl;
}
}
cout << "counter:" << counter << endl; //输出为0
}
从结果上来看,两个线程各自都进行了计数
9.copyprivate子句
代码:
#include<omp.h>
#include<iostream>
using namespace std;
//copyprivate 子句提供了一种机制用一个私有变量将一个值从一个线程广播到执行同一并行区域的其他线程
//用法:copyprivate(list)
//该子句可以关联single构造,在single构造的barrier到达之前就完成广播工作,copyprivate可以对private和threadprivate
//子句中的变量进行操作,但是当使用single构造时,copyprivate的变量不能用于private和firstprivate子句中
int counter = 0;
#pragma omp threadprivate(counter)
int in_counter()
{
counter++;
return(counter);
}
int main() {
#pragma omp parallel
{
int count;
#pragma omp single copyprivate(counter) //只有singel时,这里只有一个线程获得single构造内的赋值,有了copyprivate之后,该值私有变量被广播给其他线程
{
counter = 50;
}
count = in_counter();
cout << "Thread " << omp_get_thread_num() << ", count= " << count << endl;
}
}
最后输出每个线程的count=51。
以上文字内容和代码主要转载自:
https://blog.csdn.net/drzhouweiming/article/details/1175848
在此表示感谢!