1. OpenMP基本概念
OpenMP是一种用于共享内存并行系统的多线程程序设计方案,支持的编程语言包括C、C++和Fortran。OpenMP提供了对并行算法的高层抽象描述,特别适合在多核CPU机器上的并行程序设计。编译器根据程序中添加的pragma指令,自动将程序并行处理,使用OpenMP降低了并行编程的难度和复杂度。当编译器不支持OpenMP时,程序会退化成普通(串行)程序。程序中已有的OpenMP指令不会影响程序的正常编译运行。
2. OpenMP执行模式
OpenMP采用fork-join的执行模式。开始的时候只存在一个主线程,当需要进行并行计算的时候,派生出若干个分支线程来执行并行任务。当并行代码执行完成之后,分支线程会合,并把控制流程交给单独的主线程。
一个典型的fork-join执行模型的示意图如下:
3. OpenMP的指令
OpenMP的指令有以下一些:(常用的已标黑)
- parallel,用在一个代码段之前,表示这段代码将被多个线程并行执行
- for,用于for循环之前,将循环分配到多个线程中并行执行,必须保证每次循环之间无相关性。
- parallel for,parallel和for语句的结合,也是用在一个for循环之前,表示for循环的代码将被多个线程并行执行
- sections,用在可能会被并行执行的代码段之前
- parallel sections,parallel和sections两个语句的结合
- critical,用在一段代码临界区之前
- single,用在一段只被单个线程执行的代码段之前,表示后面的代码段将被单线程执行
- flush,用以标记一个同步点,用以确保所有的线程看到一致的存储器视图
- barrier,用于并行区内代码的线程同步,所有线程执行到barrier时要停止,直到所有线程都执行到barrier时才继续往下执行
- atomic,用于指定一块内存区域被制动更新
- master,用于指定一段代码块由主线程执行
- ordered,用于指定并行区域的循环按顺序执行
- threadprivate,用于指定一个变量是线程私有的
4. 安装
安装libgomp1
包:
sudo apt install libgomp1
安装libomp-dev
包:
sudo apt install libomp-dev
5. CMakeLists.txt编写
find_package(OpenMP REQUIRED)
target_link_libraries({project_name} OpenMP::OpenMP_CXX)
6. 使用
6.1. parallel
#include <iostream>
#include "omp.h"
using namespace std;
int main(int argc, char **argv) {
//设置线程数,一般设置的线程数不超过CPU核心数,这里开4个线程执行并行代码段
omp_set_num_threads(4);
#pragma omp parallel
{
cout << "Hello" << ", I am Thread " << omp_get_thread_num() << endl;
}
}
输出:
Hello, I am Thread 1
Hello, I am Thread 0
Hello, I am Thread 2
Hello, I am Thread 3
可以看到,OpenMP自动用4个线程调用了代码。
6.2. parallel用于for循环
#include <iostream>
#include "omp.h"
using namespace std;
int main() {
omp_set_num_threads(4);
#pragma omp parallel
for (int i = 0; i < 3; i++) {
printf("i = %d, I am Thread %d\n", i, omp_get_thread_num());
}
getchar();
}
输出:
i = 0, I am Thread 0
i = 1, I am Thread 0
i = 2, I am Thread 0
i = 0, I am Thread 0
i = 0, I am Thread 0
i = 0, I am Thread 0
i = 1, I am Thread 0
i = 2, I am Thread 0
i = 1, I am Thread 0
i = 2, I am Thread 0
i = 1, I am Thread 0
i = 2, I am Thread 0
6.2. parallel for用于for循环
#include <iostream>
#include "omp.h"
using namespace std;
int main() {
omp_set_num_threads(4);
#pragma omp parallel for
for (int i = 0; i < 3; i++) {
printf("i = %d, I am Thread %d\n", i, omp_get_thread_num());
}
getchar();
}
输出:
i = 0, I am Thread 0
i = 1, I am Thread 1
i = 2, I am Thread 2