[TOC]

概述

文章参考:http://senlinzhan.github.io/2017/06/25/openmp/

文章参考:https://zhuanlan.zhihu.com/p/51173703

什么是OpenMP?

OpenMP(Open Multi-Processing)是一个支持共享存储并行设计的库,是一个编译器指令和库函数的集合。主要是为共享式存储计算机上的并行程序设计使用的。

目前支持OpenMP的语言主要有Fortran,C/C++。

对于 CPU 密集型的程序来说,可以考虑使用 OpenMP 加快程序的计算速度。OpenMP 是跨平台的,大部分现代的 C/C++ 编译器都支持 OpenMP。OpenMP 在一定程度上对并行算法进行了抽象,因此它使用起来很方便,程序员可以简单地通过编译器指令#pragma omp去控制程序的行为。

OpenMP 的语法很简单,它看起来是这样的:

1
#pragma omp <directive> [clause[[,] clause] ...]

最常见的指令应该算是parallel指令了,紧接在parallel指令后面的那个代码块将会并行地执行:

1
2
3
4
5
6
7
8
#include <iostream>
int main() {
#pragma omp parallel
{
std::cout << "Hello, World!" << std::endl;
}
return 0;
}

程序会启用 N 个线程去执行parallel指令后面的那个代码块 (N 等同于 CPU 的核心数),执行完这个代码块之后,程序又会变回单线程。编译时只需要提供-fopenmp参数,就可以让编译器启用 OpenMP。例如,下面在双核的机器上运行这个程序,将会打印两条消息:

1
2
3
4
$ g++ -std=c++11 -fopenmp -o main main.cpp
$ ./main
Hello, World!
Hello, World!

fork/join并行执行模式的概念

OpenMP在并行执行程序时,采用的是fork/join式并行模式,共享存储式并行程序就是使用fork/join式并行的。在开始时,只有一个叫做主线程的运行线程存在 。在运行过程中,当遇到需要进行并行计算的时候,派生出(Fork)线程来执行并行任务 。在并行代码结束执行,派生线程退出或挂起,控制流程回到单独的主线程中(Join)。

执行模型

OpenMP集成

在CMake 3.9以上版本中,对OpenMP的支持得到了极大的改善。将OpenMP添加到目标中的现代(TM)方法是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 将编译生成物链接OpenMP
# Find OpenMP
if(APPLE AND USE_OpenMP)
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
set(OpenMP_C "${CMAKE_C_COMPILER}")
set(OpenMP_C_FLAGS "-Xpreprocessor -fopenmp -lomp -Wno-unused-command-line-argument")
#注意以上需要增加-Xpreprocessor 以及不能直接-llibomp 在这里不需要前缀lib只需要-lomp即可,下面相似的地方也是同个道理
set(OpenMP_C_LIB_NAMES "libomp" "libgomp" "libiomp5")
set(OpenMP_libomp_LIBRARY ${OpenMP_C_LIB_NAMES})
set(OpenMP_libgomp_LIBRARY ${OpenMP_C_LIB_NAMES})
set(OpenMP_libiomp5_LIBRARY ${OpenMP_C_LIB_NAMES})
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(OpenMP_CXX "${CMAKE_CXX_COMPILER}")
set(OpenMP_CXX_FLAGS "-Xpreprocessor -fopenmp -lomp -Wno-unused-command-line-argument")
set(OpenMP_CXX_LIB_NAMES "libomp" "libgomp" "libiomp5")
set(OpenMP_libomp_LIBRARY ${OpenMP_CXX_LIB_NAMES})
set(OpenMP_libgomp_LIBRARY ${OpenMP_CXX_LIB_NAMES})
set(OpenMP_libiomp5_LIBRARY ${OpenMP_CXX_LIB_NAMES})
endif()
endif()

if(USE_OpenMP)
find_package(OpenMP REQUIRED)
endif(USE_OpenMP)

if (OPENMP_FOUND)
include_directories("${OPENMP_INCLUDES}")
link_directories("${OPENMP_LIBRARIES}")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
endif(OPENMP_FOUND)

示例代码