[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 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" ) 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)
示例代码