并行编程OpenMP
原文链接:并行编程OpenMP基础及简单示例
一、OpenMP基本概念
OpenMP是一种用于共享内存并行系统的多线程程序设计方案,支持的编程语言包括C、C++和Fortran。OpenMP提供了对并行算法的高层抽象描述,特别适合在多核CPU机器上的并行程序设计。
编译器根据程序中添加的pragma指令,自动将程序并行处理,使用OpenMP降低了并行编程的难度和复杂度。当编译器不支持OpenMP时,程序会退化成普通(串行)程序。程序中已有的OpenMP指令不会影响程序的正常编译运行。
OpenMP通过编译指导命令来并行化,什么是编译指导命令?
简单来说就是我们平常写的#开头的语句,通过程序中插入的这些编译指导命令,计算机就会完成并行计算的工作。在C/C++程序中,OpenMP的所有的编译指导命令都是以#pragma omp开始的,后面跟具体的功能指导命令,命令形式如下:
#pragma omp 指令 子句,子句,子句……
指令可以单独出现,子句必须出现在指令之后。
二、OpenMP执行模式
(一)执行模式
OpenMP采用fork-join的执行模式。开始的时候只存在一个主线程,当需要进行并行计算的时候,派生出若干个分支线程来执行并行任务。当并行代码执行完成之后,分支线程会合,并把控制流程交给单独的主线程。
一个典型的fork-join执行模型的示意图如下:
OpenMP编程模型以线程为基础,通过编译制导指令制导并行化,有三种编程要素可以实现并行化控制,他们分别是编译制导、API函数集和环境变量。
(二)编译OpenMP程序
> gcc -fopenmp [sourcefile] -o [destination file]
> icc -openmp [sourcefile] -o [destination file]
三、编译制导
编译制导指令以#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:用于指定一个或多个变量是线程专用,后面会解释线程专有和私有的区别。
- ordered, 用亍指定并行区域的循环按顺序执行
相应的OpenMP子句为:
- rivate:指定一个或多个变量在每个线程中都有它自己的私有副本;
- firstprivate:指定一个或多个变量在每个线程都有它自己的私有副本,并且私有变量要在进入并行域或任务分担域时,继承主线程中的同名变量的值作为初值;
- lastprivate:是用来指定将线程中的一个或多个私有变量的值在并行处理结束后复制到主线程中的同名变量中,负责拷贝的线程是for或sections任务分担中的最后一个线程;
- reduction:用来指定一个或多个变量是私有的,并且在并行处理结束后这些变量要执行指定的归约运算,并将结果返回给主线程同名变量;
- nowait:指出并发线程可以忽略其他制导指令暗含的路障同步;
- num_threads:指定并行域内的线程的数目;
- schedule:指定for任务分担中的任务分配调度类型;
- shared:指定一个或多个变量为多个线程间的共享变量;
- ordered:用来指定for任务分担域内指定代码段需要按照串行循环次序执行;
- copyprivate:配合single指令,将指定线程的专有变量广播到并行域内其他线程的同名变量中;
- copyin:用来指定一个threadprivate类型的变量需要用主线程同名变量进行初始化;
- default:用来指定并行域内的变量的使用方式,缺省是shared。
四、API函数
版本为2.5的OpenMP的所有API函数
函数名 | 作用 |
omp_in_parallel | 判断当前是否在并行域中 |
omp_get_thread_num | 返回线程号 |
omp_set_num_threads | 设置后续并行域中的线程个数 |
omp_get_num_threads | 返回当前并行区域中的线程数 |
omp_get_max_threads | 获取并行域可用的最大线程数目 |
omp_get_num_procs | 返回系统中处理器个数 |
omp_get_dynamic | 判断是否支持动态改变线程数目 |
omp_set_dynamic | 启用或关闭线程数目的动态改变 |
omp_get_nested | 判断系统是否支持并行嵌套 |
omp_set_nested | 启用或关闭并行嵌套 |
omp_init(_nest) _ lock | 初始化一个(嵌套)锁 |
omp_destroy(_nest)_lock | 销毁一个(嵌套)锁 |
omp_set(_nest)_lock | (嵌套)加锁操作 |
omp_unset(_nest)_lock | (嵌套)解锁操作 |
omp_test(_nest)_lock | 非阻塞的(嵌套)加锁 |
omp_get_wtime | 获取wall time时间 |
omp_set_wtime | 设置wall time时间 |
五、环境变量
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了