OpenMP 内存模型
共享内存模型:
OpenMP 专为多处理器/核心、共享内存机器设计,底层架构可以是共享内存UMA或NUM
OpenMP 执行模型
基于线程的并行:
OpenMP 程序基于多线程来实现并行, 线程是操作系统可以调度的最小执行单元。 线程存在于单个进程的资源中,没有进程,线程就不存在。 通常,线程的数量与机器处理器/核心的数量相匹配。然而,实际使用线程的方式取决于应用程序。
显式并行化:
OpenMP 是一种显式(非自动)编程模型,使得程序员能够完全控制并行流程。
并行化可以很简单,例如串行代码加上一些编译指令,也可以以很复杂,例如多级并行,锁,甚至嵌套锁。
分叉-合并(fork-join)模型:
OpenMP 使用分叉-合并模型进行并行执行:
所有 OpenMP 程序都从主线程开始,主线程顺序执行,直到遇到第一个并行区域 结构。 然后,
分叉:主线程创建一组并行线程, 处于并行区域结构的程序,将在各个线程之间并行执行。
合并:当线程组完成并行区域结构中的语句时,它们将同步并终止,只留下主线程。
并行区域和组成它们的线程的数量是任意的。
基于编译器指令:
大多数 OpenMP 并行是通过嵌入在 C/C++ 或 Fortran 源代码中的编译器指令来指定的。
嵌套并行性:
API 允许在并行区域内嵌套并行区域。 不同实现版本可能对此功能支持不一样。
动态线程:
API 允许运行时环境动态改变线程数量以便更有效的利用资源。不同实现版本可能对此功能支持不一样。
输入/输出:
OpenMP 对并行 I/O 没有具体规定。 程序员需要自己保证在多线程程序中 I/O 的正确性。
执行模型和内存模型的相互作用:
单程序多数据(SPMD)是基本的编程范式,所有线程都有执行相同程序代码的潜力,但是每个线程可能访问、修改不同的数据并遍历不同的执行路径。
OpenMP 提供了“松弛一致性”和“临时"线程内存视图。线程可以平等地访问共享内存,共享内存中的变量可以被检索/存储。每个线程还有自己的临时变量副本,可以独立于内存中的变量进行修改。 当所有线程都需要对共享变量具有一致的视图时,程序员(或编译器)需要确保所有的线程都更新了此变量。
OpenMP 编程主要内容:
- 启动并行线程的方法
- 统计正在运行的线程数量的方法
- 唯一标识线程的方式
- 将线程汇合(join),进行串行执行的方法
- 同步线程的方法
- 当必要时确保对数据项的一致视图
- 必须检查数据依赖性、数据冲突、条件竞争或死锁