OpenMP基本概念

2023-05-16

 

OpenMP是一种用于共享内存并行系统的多线程程序设计方案,支持的编程语言包括C、C++和Fortran。OpenMP提供了对并行算法的高层抽象描述,特别适合在多核CPU机器上的并行程序设计。编译器根据程序中添加的pragma指令,自动将程序并行处理,使用OpenMP降低了并行编程的难度和复杂度。当编译器不支持OpenMP时,程序会退化成普通(串行)程序。程序中已有的OpenMP指令不会影响程序的正常编译运行。

 

在VS中启用OpenMP很简单,很多主流的编译环境都内置了OpenMP。在项目上右键->属性->配置属性->C/C++->语言->OpenMP支持,选择“是”即可。

 

OpenMP执行模式

 

OpenMP采用fork-join的执行模式。开始的时候只存在一个主线程,当需要进行并行计算的时候,派生出若干个分支线程来执行并行任务。当并行代码执行完成之后,分支线程会合,并把控制流程交给单独的主线程。

一个典型的fork-join执行模型的示意图如下:

 

 

OpenMP编程模型以线程为基础,通过编译制导指令制导并行化,有三种编程要素可以实现并行化控制,他们分别是编译制导、API函数集和环境变量。

 

编译制导

 

编译制导指令以#pragma omp 开始,后边跟具体的功能指令,格式如:#pragma omp 指令[子句[,子句] …]。常用的功能指令如下:

  • parallel:用在一个结构块之前,表示这段代码将被多个线程并行执行;
    for:用于for循环语句之前,表示将循环计算任务分配到多个线程中并行执行,以实现任务分担,必须由编程人员自己保证每次循环之间无数据相关性;
    parallel for:parallel和for指令的结合,也是用在for循环语句之前,表示for循环体的代码将被多个线程并行执行,它同时具有并行域的产生和任务分担两个功能;
    sections:用在可被并行执行的代码段之前,用于实现多个结构块语句的任务分担,可并行执行的代码段各自用section指令标出(注意区分sections和section);
    parallel sections:parallel和sections两个语句的结合,类似于parallel for;
    single:用在并行域内,表示一段只被单个线程执行的代码;
    critical:用在一段代码临界区之前,保证每次只有一个OpenMP线程进入;
    flush:保证各个OpenMP线程的数据影像的一致性;
    barrier:用于并行域内代码的线程同步,线程执行到barrier时要停下等待,直到所有线程都执行到barrier时才继续往下执行;
    atomic:用于指定一个数据操作需要原子性地完成;
    master:用于指定一段代码由主线程执行;
    threadprivate:用于指定一个或多个变量是线程专用,后面会解释线程专有和私有的区别。

 

相应的OpenMP子句为: 


  • private:指定一个或多个变量在每个线程中都有它自己的私有副本;
    firstprivate:指定一个或多个变量在每个线程都有它自己的私有副本,并且私有变量要在进入并行域或任务分担域时,继承主线程中的同名变量的值作为初值;
    lastprivate:是用来指定将线程中的一个或多个私有变量的值在并行处理结束后复制到主线程中的同名变量中,负责拷贝的线程是for或sections任务分担中的最后一个线程; 
    reduction:用来指定一个或多个变量是私有的,并且在并行处理结束后这些变量要执行指定的归约运算,并将结果返回给主线程同名变量;
    nowait:指出并发线程可以忽略其他制导指令暗含的路障同步;
    num_threads:指定并行域内的线程的数目; 
    schedule:指定for任务分担中的任务分配调度类型;
    shared:指定一个或多个变量为多个线程间的共享变量;
    ordered:用来指定for任务分担域内指定代码段需要按照串行循环次序执行;
    copyprivate:配合single指令,将指定线程的专有变量广播到并行域内其他线程的同名变量中;
    copyin:用来指定一个threadprivate类型的变量需要用主线程同名变量进行初始化;
    default:用来指定并行域内的变量的使用方式,缺省是shared。

 

API函数

 

除上述编译制导指令之外,OpenMP还提供了一组API函数用于控制并发线程的某些行为,下面是一些常用的OpenMP API函数以及说明: 

 

环境变量

 

OpenMP中定义一些环境变量,可以通过这些环境变量控制OpenMP程序的行为,常用的环境变量:

  • OMP_SCHEDULE:用于for循环并行化后的调度,它的值就是循环调度的类型;  
    OMP_NUM_THREADS:用于设置并行域中的线程数;   
    OMP_DYNAMIC:通过设定变量值,来确定是否允许动态设定并行域内的线程数;  
    OMP_NESTED:指出是否可以并行嵌套。 

 

简单示例之parallel使用

 

parallel制导指令用来创建并行域,后边要跟一个大括号将要并行执行的代码放在一起:

 


   
  1. #include<iostream>

  2. #include"omp.h"

  3.  
  4. using namespace std;

  5.  
  6. void main()

  7. {

  8. #pragma omp parallel

  9. {

  10. cout << "Test" << endl;

  11. }

  12. system("pause");

  13. }

 

 

执行以上程序有如下输出:

 

程序打印出了4个“Test”,说明parallel后的语句被4个线程分别执行了一次,4个是程序默认的线程数,还可以通过子句num_threads显式控制创建的线程数:

 


   
  1. #include<iostream>

  2. #include"omp.h"

  3.  
  4. using namespace std;

  5.  
  6. void main()

  7. {

  8. #pragma omp parallel num_threads(6)

  9. {

  10. cout << "Test" << endl;

  11. }

  12. system("pause");

  13. }

 

 

编译运行有如下输出:

 

程序中显式定义了6个线程,所以parallel后的语句块分别被执行了6次。第二行的空行是由于每个线程都是独立运行的,在其中一个线程输出字符“Test”之后还没有来得及换行时,另一个线程直接输出了字符“Test”。

 

简单示例之parallel for使用

 

使用parallel制导指令只是产生了并行域,让多个线程分别执行相同的任务,并没有实际的使用价值。parallel for用于生成一个并行域,并将计算任务在多个线程之间分配,从而加快计算运行的速度。可以让系统默认分配线程个数,也可以使用num_threads子句指定线程个数。

 


   
  1. #include<iostream>

  2. #include"omp.h"

  3.  
  4. using namespace std;

  5.  
  6. void main()

  7. {

  8. #pragma omp parallel for num_threads(6)

  9. for (int i = 0; i < 12; i++)

  10. {

  11. printf("OpenMP Test, 线程编号为: %d\n", omp_get_thread_num());

  12. }

  13. system("pause");

  14. }

 

 

运行输出:

 

上边程序指定了6个线程,迭代量为12,从输出可以看到每个线程都分到了12/6=2次的迭代量。

 

OpenMP效率提升以及不同线程数效率对比

 

 


   
  1. #include<iostream>

  2. #include"omp.h"

  3.  
  4. using namespace std;

  5.  
  6. void test()

  7. {

  8. for (int i = 0; i < 80000; i++)

  9. {

  10. }

  11. }

  12.  
  13. void main()

  14. {

  15. float startTime = omp_get_wtime();

  16.  
  17. //指定2个线程

  18. #pragma omp parallel for num_threads(2)

  19. for (int i = 0; i < 80000; i++)

  20. {

  21. test();

  22. }

  23. float endTime = omp_get_wtime();

  24. printf("指定 2 个线程,执行时间: %f\n", endTime - startTime);

  25. startTime = endTime;

  26.  
  27. //指定4个线程

  28. #pragma omp parallel for num_threads(4)

  29. for (int i = 0; i < 80000; i++)

  30. {

  31. test();

  32. }

  33. endTime = omp_get_wtime();

  34. printf("指定 4 个线程,执行时间: %f\n", endTime - startTime);

  35. startTime = endTime;

  36.  
  37. //指定8个线程

  38. #pragma omp parallel for num_threads(8)

  39. for (int i = 0; i < 80000; i++)

  40. {

  41. test();

  42. }

  43. endTime = omp_get_wtime();

  44. printf("指定 8 个线程,执行时间: %f\n", endTime - startTime);

  45. startTime = endTime;

  46.  
  47. //指定12个线程

  48. #pragma omp parallel for num_threads(12)

  49. for (int i = 0; i < 80000; i++)

  50. {

  51. test();

  52. }

  53. endTime = omp_get_wtime();

  54. printf("指定 12 个线程,执行时间: %f\n", endTime - startTime);

  55. startTime = endTime;

  56.  
  57. //不使用OpenMP

  58. for (int i = 0; i < 80000; i++)

  59. {

  60. test();

  61. }

  62. endTime = omp_get_wtime();

  63. printf("不使用OpenMP多线程,执行时间: %f\n", endTime - startTime);

  64. startTime = endTime;

  65.  
  66. system("pause");

  67. }

 

 

以上程序分别指定了2、4、8、12个线程和不使用OpenMP优化来执行一段垃圾程序,输出如下:

 

可见,使用OpenMP优化后的程序执行时间是原来的1/4左右,并且并不是线程数使用越多效率越高,一般线程数达到4~8个的时候,不能简单通过提高线程数来进一步提高效率。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OpenMP基本概念 的相关文章

  • linux中终端命令行“删除在光标之前的所有字符“快捷键

    可以使用快捷键 34 Ctrl 43 U 34 xff0c 该快捷键能够删除在光标之前的所有字符 xff0c 包括命令行参数 如果您想要还原这些被删除的字符 xff0c 可以使用快捷键 34 Ctrl 43 Y 34
  • 开发机Python HTTP服务器

    目录下执行下载py文件 xff0c wget http 10 138 59 50 8080 HttpServer py 执行 xff0c nohup python2 HttpServer py 8081 amp 浏览器打开 ip 8081
  • C/C++封装socket通信类

    C C 43 43 封装socket通信类 一 读取 写入数据1 recvn函数2 sendn函数3 TcpRecv函数4 TcpSend函数 二 C的封装方法1 客户端2 服务端 三 C 43 43 的封装方法1 客户端2 服务端 不管是
  • Invalid prop: custom validator check failed for prop “value“

    问题描述 看见这种大片的爆红 xff0c 就两个字 xff1a 头疼 xff01 xff01 xff01 虽然这样的爆红不影响程序运行 xff0c 但是作为一个合格的程序猿 xff0c 我们怎么可以允许这个问题出现呢 x1f60e 问题排查
  • 如何计算UDP/TCP检验和checksum

    一 下面的图是一个UDP的检验和所需要用到的所有信息 xff0c 包括三个部分 xff1a 1 UDP伪首部 2 UDP首部 3 UDP的数据部分 xff08 切记不要遗漏该部分 xff0c 否则就 吐血了 xff09 首先解释下伪首部的概
  • 日常生活小技巧 -- UART (串口)回环测试

    转自https blog csdn net qq 29350001 article details 77335721 新买的USB转串口线 需要测试一下是否是OK的 该如何测试 xff1f 其实很简单 xff0c 就是讲 Tx 和 Rx 短
  • C/C++:头文件与cpp文件的声明/定义

    一 头文件 1 一般来说 xff0c 头文件仅仅用于声明 xff0c 相应的定义要放在对应的cpp文件中 声明的内容一般可以是 xff1a 1 类定义体 xff1b 2 类中的成员方法 xff1b 3 类外的函数 xff1b 4 类外的变量
  • 树莓派简易人脸追踪云台

    前言 xff1a 这篇文章属于此系列 xff1a 一个用树莓派做的会聊天 xff0c 能人脸识别 xff08 支持云台追踪 xff09 和发送邮件的小玩具 https blog csdn net yonglisikao article de
  • Android JNI调用概要

    一 Java调C 编写Native方法 使用javah命令生成 h头文件 复制 h头文件到CPP工程中 复制jni md h和jni h到CPP工程中 实现 h头文件中生成的 生成dll文件 C的函数名称 xff1a Java 包名 方法名
  • curl的请求头与响应头获取

    1 从CURL中获取响应头 oCurl 61 curl init 设置请求头 有时候需要 有时候不用 看请求网址是否有对应的要求 header 61 34 Content type application x www form urlenc
  • C++头文件包含顺序问题

    C 43 43 中类的声明和类的定义分开几乎成了一个不成文的规定 这样做的好处是使得类的声明和实现分开 xff0c 清晰明了 xff0c 同时便于库函数发布 但是在实际编程中由此也常常引起了一些由于头文件的包含顺序问题而产生的符号未定义的编
  • 详解printf重定向到文件中,打印日志的实现

    printf是将信息打印到终端 xff0c 但是有时当我们需要打印的信息比较多时 xff0c 终端无法将所有信息都能够保留在屏幕上 xff0c 这样我们就不能在终端获取我们想要的信息了 xff0c 重定向很好的帮我们解决了这个问题 xff0
  • 计划

    文档计划 读书的时候 2010年左右 由于和导师做了一些涉及单片机的项目 xff0c 狠狠熟悉了一把C语言 xff0c 所以试图写一个实时内核 xff0c 但是由于涉及大量的硬件知识 xff0c 底层汇编和任务栈之类的东西 xff0c 而这
  • CMOS内核--序言

    CMOS内核 序言 本文介绍一些CMOS中需要用的基础知识 由于在单片机系统中不会有MMU所以单片机系统中的每个任务就是一个线程 xff0c 共用系统的地址空间 xff0c 为了精确性 xff0c 后文中措辞中使用线程替换任务 xff0c
  • 欧拉角和旋转矩阵之间的转换

    一 什么是欧拉角 在3D 空间中 xff0c 表示物体的旋转可以由三个欧拉角来表示 xff1a pitch围绕X轴旋转 xff0c 叫俯仰角 yaw围绕Y轴旋转 xff0c 叫偏航角 roll围绕Z轴旋转 xff0c 叫翻滚角 这三个角的顺
  • C++编译之(1)-g++单/多文件/库的编译及C标准的发展历程

    g 43 43 编译入门 本文为您介绍g 43 43 的编译用法 xff1b 通过从最简单的单文件编译 xff0c 到多文件编译 xff0c 再到动态库 静态库的编译及使用 xff1b 例子都经过实际编译并运行 xff0c 可谓全网最良心之
  • STM32F103-寄存器开发-2

    上一篇博客中我已经配置好了对应的时钟 xff0c 接下来就是对GPIOC口进行操作了 为此我们需要配置端口配置寄存器 xff0c 但是在用户手册中查阅 xff0c 可以发现有两个寄存器 xff0c CRL和CRH xff0c 我们应该使用哪
  • 25.UART串口发送过程与配置

    UART串口收发过程与配置 参考资料 STM32Fx中文参考手册 第26章 xff1a 通用同步异步收发器章节 开发板配套教程 STM32Fx开发指南 串口实验章节 笔记基于正点原子官方视频 视频连接https www bilibili c
  • c语言HTTP服务器,超级简易版。

    算是对linux多线程的复习把 xff0c 尝试这用socket写了一个简单的HTTP服务器 xff0c 当访问它的时候它会给你发送一个HTML文件 xff0c 这个HTML文件需要自己写 代码 span class hljs prepro
  • linux POST请求

    linux POST请求 curl https baidu com X POST H key1 value1 H key2 value2 d name test age 23 i 说明 xff1a H header 后接key value对

随机推荐

  • CPPREST处理跨域问题

    本例使用的代码框架非常简单 按照下面这个路径搭建即可 https blog csdn net youyicc article details 108261287 问题由来 网页端需要动态检测C 服务器这边服务是否正常运行 所以采用的方式是h
  • 内存存取区——堆和栈

    一 预备知识 程序的内存分配 一个由c C 43 43 编译的程序占用的内存分为以下几个部分 1 栈区 xff08 stack xff09 由编译器自动分配释放 xff0c 存放函数的参数值 xff0c 局部变量的值等 其操作方式类似于数据
  • ROS中RVIZ坐标系及TF坐标系转换

    RVIZ坐标系 X轴 红色 Y轴 绿色 Z轴 蓝色 YAW 偏航角 绕Z轴旋转 PITCH 俯仰角 绕Y轴旋转 ROLL 滚转角 绕X轴旋转 符合右手坐标系原则 利用TF进行坐标系转换 采用以下指令进行转换 xff0c 其中frame id
  • 【C语言】长度为0的数组

    最近在看代码的时候发现一个好玩的事情 xff0c 长度为0的数组 xff0c 在此记录一下 在网上看到的这个说是只有GNU C才支持的特性 xff0c 因此考虑跨平台或者可移植特点需要慎用 话不多说 xff0c 上案例才有感觉 span c
  • jetson xavier nx使用usb线刷机后开机黑屏闪屏

    情况一 比较常见 xff09 由于刷机是的flash接口是调在右边的 xff0c 如下图所示 解决方法 xff1a 故在刷机成功后 xff0c 连接显示屏后要将flash接口调到 左侧 情况二 在对jetson xavier nxs进行刷机
  • python牛客网输入输出处理

    python 笔试输入 sys stdin readline和input 非常有用 xff01 xff01 xff09 https www jianshu com p 6f14ca3290ee input vs sys stdin read
  • Demo-简单使用libcurl静态库访问网址

    在开始前请先准备好下面的文件 xff1a 1 调试版的libcurl静态库libcurld lib xff0c 可以在网上下载或自己编译 xff1b 2 头文件 xff0c curl h curlver h easy h mprintf h
  • QQ 浏览器(iOS版)崩溃信息研究

    今天碰巧下载了QQ浏览器iOS版本 xff0c 居然一启动就挂了 后来从手机里面把崩溃信息导出来 xff0c 仔细研究下 xff0c 把研究的结果放到网上 xff0c 与大家分享下 先把我导出的崩溃信息放出来 Incident Identi
  • EXCEL利用VBA自由控制图表绘图区大小

    用好VBA的话确实可以给你再办公室的工作效率带来质的提升 如果有人跟你说你可以用Python什么的语言处理Excel balabala的 xff0c 你可以无视他了 当然python可以处理很多事情 xff0c 但是EXCEL自带的作图工具
  • 提升CUDA程序运行效率的几个关键点

    目录 1 明确计算机中GPU卡片的计算资源 xff0c 决定变量的性质 xff08 constant xff0c share还是global xff09 以及Grid xff0c Block的维度 xff0c 充分并合理利用GPU显卡的资源
  • CUDA程序编写具体参数设置

    介绍了GPU的结构以及资源的控制要素 xff08 GPU硬件结构和程序具体参数设置 yu132563的专栏 CSDN博客 xff09 以及编程过程中的一些需要注意的问题 xff08 CUDA程序性能调优 yu132563的专栏 CSDN博客
  • CUDA Stream流并发性

    目录 1 CUDA 中的异步命令 2 默认流 3 Multistream多流示例 异构计算是指高效地使用系统中的所有处理器 xff0c 包括 CPU 和 GPU 为此 xff0c 应用程序必须在多个处理器上并发执行函数 CUDA 应用程序通
  • Madagascar环境下编程

    引用 原创 Madagascar环境下编程 2013 07 17 04 50 34 转载 标签 xff1a 教育 分类 xff1a madagascar 本文转载自seismig 原创 Madagascar环境下编程 Madagascar是
  • mySQL(关系型数据库管理系统)编辑

    收藏 2906 1034 mySQL xff08 关系型数据库管理系统 xff09 编辑 MySQL 1 是一个 关系型数据库管理系统 xff0c 由瑞典 MySQL AB公司开发 xff0c 目前属于 Oracle公司 MySQL是最流行
  • CPU的核心数、线程数的关系和区别

    我们在选购电脑的时候 xff0c CPU是一个需要考虑到核心因素 xff0c 因为它决定了电脑的性能等级 CPU从早期的单核 xff0c 发展到现在的双核 xff0c 多核 CPU除了核心数之外 xff0c 还有线程数之说 xff0c 下面
  • STM32单片机,下载器下载完程序能正常跑起来,断电再上电程序不运行

    晶振坏了 转载于 https www cnblogs com god of death p 7050281 html
  • CUDA性能优化----warp深度解析

    CUDA性能优化 warp深度解析 2017 01 12 16 41 07 分类 xff1a HPC amp CUDA优化 标签 xff1a gpu cuda hpc 举报 字号 订阅 下载LOFTER 我的照片书 1 引言 CUDA性能优
  • 螺旋桨转矩

    xfeff xfeff 在螺旋桨气动力分析时 xff0c 首先应用翼型理论进行螺旋桨叶素分析 利用翼型升阻特性数据 xff0c 回避了有限机翼的展弦比问题 xff0c 诱导流动由涡流模型确定 xff0c 取决于桨叶数目 间距以及作用于每片桨
  • 给初学者们讲解人工神经网络(ANN)

    1 介绍 这份教学包是针对那些对人工神经网络 xff08 ANN xff09 没有接触过 基本上完全不懂的一批人做的一个简短入门级的介绍 我们首先简要的引入网络模型 xff0c 然后才开始讲解ANN的相关术语 作为一个应用的案例 xff0c
  • OpenMP基本概念

    OpenMP是一种用于共享内存并行系统的多线程程序设计方案 xff0c 支持的编程语言包括C C 43 43 和Fortran OpenMP提供了对并行算法的高层抽象描述 xff0c 特别适合在多核CPU机器上的并行程序设计 编译器根据程序