OpenMP并行程序设计之常用子句使用介绍(二)
2017-02-26 20:57
477 查看
OpenMP并行程序设计之常用子句使用介绍(二)
承接上面的博客,这次还要介绍三个OpenMP并行程序设计的数据处理子句,threadprivate子句,reduction子句以及sections子句。
1. threadprivate子句
这个子句理解较为简单,作用呢,就是对于一些全局变量,可以使用这条指令,使得每一个线程都能有此全局变量的独立的拷贝,并且互相不影响。需要注意的是,该指令所指示的一定是全局变量,即在全程序是有效的,而且是永久变量,在多个并行域内都有效。我们代码走起。
从上面的程序以及运行结果可以看出,有两个并行域,两个并行域共享全局变量g,而且在各自并行域中各个线程共享变量g,但是在各个线程中g值的输出是互不影响的,是相互独立的。
2. reduction子句
在介绍这个子句之前,请先看下面示例
诶,为什么会出现这样的运行结果呢,按理来说,每次执行test()函数,得到的sum的求和值应该都是55啊,为啥还会出现27,47,40,42呢。之所以会出现上述错误的输出结果就是因为存在数据竞争的问题。这应该是所有多线程编程中最为棘手的问题了,那么对于这样的并行处理求和该怎么办呢,reduction子句就能派上用场。我们对上面的代码做一些小的修改,我们在#pragma
omp parallel for 后面加上了 reduction(+:sum)。代码如下:
从上面的运行结果可以看出,所有结果都是正确的。reduction(+:sum)它的意思是告诉编译器:下面的for循环你要分成多个线程跑,但每个线程都要保存变量sum的拷贝,循环结束后,所有线程把自己的sum累加起来作为最后的输出。
3. section子句和sections子句
section语句是用在sections语句里用来将sections语句里的代码划分成几个不同的段,每段都并行执行。用法如下:
下面我们来看个实例吧,代码最具有说服力,最能让人理解。
程序运行结果如下:
从结果中可以发现第3段代码执行比第2段代码早,说明各个section里的代码都是并行执行的,并且各个section被分配到不同的线程执行。使用section语句时,需要注意的是这种方式需要保证各个section里的代码执行时间相差不大,否则某个section执行时间比其他section过长就达不到并行执行的效果了。
上面的代码也可以改写成以下形式:
程序运行结果:
这种方式和前面那种方式的区别是,两个sections语句是串行执行的,即第二个sections语句里的代码要等第一个sections语句里的代码执行完后才能执行。个人认为OpenMP并行程序设计比较常用的数据子句也就这些,当然还有其他子句了,比如copyin,default等等。
参考文献: http://blog.csdn.net/gengshenghong/article/details/6969957 http://blog.csdn.net/wangzhebupt/article/details/22743515
承接上面的博客,这次还要介绍三个OpenMP并行程序设计的数据处理子句,threadprivate子句,reduction子句以及sections子句。
1. threadprivate子句
这个子句理解较为简单,作用呢,就是对于一些全局变量,可以使用这条指令,使得每一个线程都能有此全局变量的独立的拷贝,并且互相不影响。需要注意的是,该指令所指示的一定是全局变量,即在全程序是有效的,而且是永久变量,在多个并行域内都有效。我们代码走起。
#include<iostream> #include <omp.h> int g;//全局变量 #pragma omp threadprivate(g) //声明变量线程私有 int main(int argc, char *argv[]) { /* Explicitly turn off dynamic threads */ //omp_set_dynamic(0); printf("Masterthread started\n\n"); #pragma omp parallel { g = omp_get_thread_num(); printf("tid: %d\n", g); } // End of parallel region #pragma omp parallel { int temp = g*g; printf("tid : %d, tid*tid: %d\n", g, temp); } // End of parallel region printf("Masterthread finished\n"); system("pause"); return(0); }程序运行结果如下:
从上面的程序以及运行结果可以看出,有两个并行域,两个并行域共享全局变量g,而且在各自并行域中各个线程共享变量g,但是在各个线程中g值的输出是互不影响的,是相互独立的。
2. reduction子句
在介绍这个子句之前,请先看下面示例
#include <iostream> void test() { int sum = 0; int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; #pragma omp parallel for for (int i = 0; i < 10; i++) sum = sum + a[i]; std::cout << "sum: " << sum << std::endl; } int main() { for (int i = 0; i < 10; i++) test(); system("pause"); return 0; }程序运行结果如下:
诶,为什么会出现这样的运行结果呢,按理来说,每次执行test()函数,得到的sum的求和值应该都是55啊,为啥还会出现27,47,40,42呢。之所以会出现上述错误的输出结果就是因为存在数据竞争的问题。这应该是所有多线程编程中最为棘手的问题了,那么对于这样的并行处理求和该怎么办呢,reduction子句就能派上用场。我们对上面的代码做一些小的修改,我们在#pragma
omp parallel for 后面加上了 reduction(+:sum)。代码如下:
#include <iostream> void test() { int sum = 0; int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; #pragma omp parallel for reduction(+:sum) for (int i = 0; i < 10; i++) sum = sum + a[i]; std::cout << "sum: " << sum << std::endl; } int main() { for (int i = 0; i < 10; i++) test(); system("pause"); return 0; }程序运行结果如下:
从上面的运行结果可以看出,所有结果都是正确的。reduction(+:sum)它的意思是告诉编译器:下面的for循环你要分成多个线程跑,但每个线程都要保存变量sum的拷贝,循环结束后,所有线程把自己的sum累加起来作为最后的输出。
3. section子句和sections子句
section语句是用在sections语句里用来将sections语句里的代码划分成几个不同的段,每段都并行执行。用法如下:
#pragma omp [parallel] sections [子句] { #pragma omp section { 代码块 } }
下面我们来看个实例吧,代码最具有说服力,最能让人理解。
#include <iostream> #include<omp.h> int main(int argc, char *argv) { #pragma omp parallel sections { #pragma omp section printf("section 1 ThreadId = %d\n", omp_get_thread_num()); #pragma omp section printf("section 2 ThreadId = %d\n", omp_get_thread_num()); #pragma omp section printf("section 3 ThreadId = %d\n", omp_get_thread_num()); #pragma omp section printf("section 4 ThreadId = %d\n", omp_get_thread_num()); } system("pause"); return 0; }
程序运行结果如下:
从结果中可以发现第3段代码执行比第2段代码早,说明各个section里的代码都是并行执行的,并且各个section被分配到不同的线程执行。使用section语句时,需要注意的是这种方式需要保证各个section里的代码执行时间相差不大,否则某个section执行时间比其他section过长就达不到并行执行的效果了。
上面的代码也可以改写成以下形式:
#include <iostream> #include<omp.h> int main(int argc, char *argv) { #pragma omp parallel { #pragma omp sections//sections 1 { #pragma omp section printf("section 1 ThreadId = %d\n", omp_get_thread_num()); #pragma omp section printf("section 2 ThreadId = %d\n", omp_get_thread_num()); } #pragma omp sections { #pragma omp section//sections 2 printf("section 3 ThreadId = %d\n", omp_get_thread_num()); #pragma omp section printf("section 4 ThreadId = %d\n", omp_get_thread_num()); } } system("pause"); return 0; }
程序运行结果:
这种方式和前面那种方式的区别是,两个sections语句是串行执行的,即第二个sections语句里的代码要等第一个sections语句里的代码执行完后才能执行。个人认为OpenMP并行程序设计比较常用的数据子句也就这些,当然还有其他子句了,比如copyin,default等等。
参考文献: http://blog.csdn.net/gengshenghong/article/details/6969957 http://blog.csdn.net/wangzhebupt/article/details/22743515
相关文章推荐
- OpenMP并行程序设计之常用子句使用介绍(一)
- VC上使用OpenMP并行程序设计的配置
- OpenMP并行程序设计之OpenMP使用入门
- Android之常用Tools【介绍及使用】
- 常用加密解密算法【RSA、AES、DES、MD5】介绍和使用
- 关于MacBook Air电脑一些常用快捷键的使用的介绍
- 二十二、标准库类型vector的使用、vector介绍、vector构造和初始化、vector常用成员函数
- OpenMP并行程序设计——for循环并行化详解
- js中函数调用的两种常用方法使用介绍
- 3、 Linux的常用命令:常用命令的介绍、常用命令的使用和练习
- RDLC使用手册_RDLC常用控件介绍(Matrix)(转)
- RDLC使用手册_RDLC常用控件介绍(SubReport)
- Apache Maven的入门使用之常用操作以及核心概念介绍(2)
- TestDriven.Net常用属性介绍及使用
- OpenMP并行构造的schedule子句详解
- 【工具】【sublime text3】基本使用及常用插件介绍
- 卷积神经网络CNN与深度学习常用框架的介绍与使用
- 对称加密算法之RC4介绍及OpenSSL中RC4常用函数使用举例
- 介绍使用WordPress时10个常用的MySQL查询
- Oracle常用SQL技巧SELECT子句中避免使用