目录
KI
随便写写,最近学并行与分布式计算课程对openmp的相关知识和使用有点混乱。
编程模型
在计算领域,并行编程模型是并行计算机体系架构的一种抽象,它便于编程人员在程序中编写算法及其组合。
OpenMP简介
OpenMP是一套支持跨平台共享内存方式的多线程并发的编程API,基于Fork-Join模型。
基本逻辑:一个openmp程序是由一个进程发起的,起初该进程只有一个主线程,在使用并行指导语句创建并行区域,进程fork出多个轻量级的线程,每个线程都执行并行区域中的代码。并行区域结束后,只有主线程继续执行。
在并行区域内,变量分为两种:私有变量(存放于独立的线程的栈中),共享变量(定义与共享内存空间,所以线程可访问)。
openmp基本语法
parallel region
在并行区域中 默认变量是共享的,所有的线程执行同样的代码,并且结尾有显示的同步操作。
关于并行区域中的变量:
- private,如果一个变量是private的,则每个线程都有自己私有变量的本地副本。(可以理解为openmp赋值了这个变量,并将本地副本分配给每一个线程,保存在各自线程的栈中)
- share,如果一个变量是share的,则存在一个实例,在所有线程中共享。(针对共享变量,需要考虑数据竞争的问题)
关于变量的类型确定
- 在并行区域之外声明的变量没有特别指定默认是共享的。
- 循环迭代的变量默认是私有的;并行区域之内声明的变量默认为私有的。
- 使用shared子句声明变量为共享的。
- 使用private子句声明变量为私有的。
- default(shared):当使用这个指令时,它会告诉OpenMP编译器,除非明确另行指定,所有在并行区域内定义的变量都应该被视为共享的。默认情况下,如果没有明确指定变量的共享属性,OpenMP通常会将在并行区域内定义的变量标记为共享变量。使用
default(shared)
指令可以明确指定这一点,以确保在并行区域内的变量都被视为共享变量。- default(none):表示必须显式指定所有共享变量的数据属性,否则会报错,除非变量有明确的属性定义(比如循环并行区域的循环迭代变量只能是私有的)
关于并行变量的其他情况声明
- 针对于迭代变量,就算声明为shared,在并行for语句里也默认为私有变量。
- 对于共享变量,存在数据竞争问题,对共享变量进行写的时候,无法确定线程何时写,会不会存在两个线程以上同时写的情况。
如果变量的状态是 PRIVATE ,那么它会在线程的stack 中。它的值在进入并行区域时是不确定的。
并行区域的其他子句
- firsprivate使私有变量初始化为并行区域开始时的数值。如:#pragma omp parallel firstprivate(a),a继承它在并行区域外的值
lastprivate 使变量私有,同时将它赋值为循环最后一次迭代的数值 reduction 每个线程有 private 的副本, reduction 为共享变量在每个线程创建私有副本,变量会将操作作用在所有的私有共享变量(私有副本)上,最终结果写回全局共享变量。(理解为:将共享变量变为私有变量,每个线程的私有变量完成其任务后返回,使用reduction指定的操作累计到原全局共享变量)
Work sharing
使用OpenMP创建并行区域,程序员需要显式地对任务(work)和数据进行划分,来保证没有数据竞争(data race)
相关指导语句
- for ,如:#pragma omp parallel for。(使用for后,在并行区域,并不是所有的线程都执行一次后面的for语句,而是将for语句按调度策略分配到不同的线程,并行执行)
for 语句后会有隐式的 barrier ,除非有语句 NOWAIT
调度策略
语句形式:#pragma omp for schedule(static|dynamic|guided)
Schedule(static, chunk_size ) 循环迭代以 chunk_size 分为不同的组( chunk ),各组以循环的方式分配给不同的线程如果chunk_size没有指定,则默认使各 chunk 尽可能均衡 Schedule(dynamic, chunk_size ) 循环迭代以 chunk_size 为单位分配给各线程。各线程完成对应的chunk 后申请执行新的 chunk Schedule(guided, chunk_size ) 调度是一种采用指导性的启发式自调度方法。开始时每个线程会分配到较大的迭代块,之后分配到的迭代块会逐渐递减。迭代块的大小会按指数级下降到指定的chunk_size 大小
Exclusive Execution
指导语句
- SINGLE语句使相应的并行区域中只有一个线程在执行;如果没有NOWAIT语句,其他的线程等待直到SINGLE语句对应的区域执行完成。如:#pragma omp single nowait
- single语句配合copyprivate使用可以将该变量的值广播到其他线程。如:#pragma omp single copyprivate(a)
MASTER 语句创建的区域由 master线程执行;MASTER区域结尾没有隐式同步。如: #pragma omp master
Synchronization
PARALLEL和
FOR
创建区域结束时都有隐式同步
;
barrier
可以通过
NOWAIT
语句绕过。
指导语句
- 通过barrier语句来显示同步,即需要所以线程都执行到这里。如:#pragma omp barrier
ATOMIC 语句能够保证内存中的共享存储位置在某时刻只被同一线程修改(原子操作) CRITICAL 语句保证程序的特定区域一个时刻只有一个线程执行
Nested Parallelism
嵌套并行指在一个并行区域中嵌套另一个并行区域。
openmp程序接口
omp_set_num_threads(): 设定并行区域中的线程数目omp_get_num_threads(): 返回并行区域中的线程数目omp_get_thread_num():返回目前组中的当前线程的 IDomp_get_max_threads():返回并行区域中可以创建的最大线程数目omp_in_parallel(): 判断是否在并行区域中omp_set_nested(): 设置并行区域嵌套omp_get_nested():判断是否允许嵌套
环境变量
OMP_NUM_THREADS: 并行区域中最大的线程数目OMP_NESTED:是否允许 OpenMP 嵌套并行