今天在工作时看到一段代码:1
2
3
4#pragma omp parallel for
for(……){
……
}
开始还以为是写错的注释,查了一下发现是一种简单的并行实现方式。
OpenMP 是 Open MultiProcessing 的缩写。OpenMP 并不是一个简单的函数库,而是一个诸多编译器支持的框架,或者说是协议吧,总之,不需要任何配置,你就可以在 Visual Studio 或者 gcc 中使用它了。
OpenMP是由OpenMP Architecture Review Board牵头提出的,并已被广泛接受,用于共享内存并行系统的多处理器程序设计的一套指导性编译处理方案(Compiler Directive) [1] 。OpenMP支持的编程语言包括C、C++和Fortran;而支持OpenMp的编译器包括Sun Compiler,GNU Compiler和Intel Compiler等。OpenMp提供了对并行算法的高层的抽象描述,程序员通过在源代码中加入专用的pragma来指明自己的意图,由此编译器可以自动将程序进行并行化,并在必要之处加入同步互斥以及通信。当选择忽略这些pragma,或者编译器不支持OpenMp时,程序又可退化为通常的程序(一般为串行),代码仍然可以正常运作,只是不能利用多线程来加速程序执行。OpenMP
简单来说,OpenMP是一个支持共享存储并行设计的库,特别适宜多核CPU上的并行程序设计。
在C++中,OpenMP的指令格式为:#pragma omp 指令[子句[子句]…],比如:1
2#pragma omp parallel for num_threads(FLAGS_num_threads)
for(……){}
常用指令
- parallel,用在一个代码段之前,表示这段代码将被多个线程并行执行
- for,用于for循环之前,将循环分配到多个线程中并行执行,必须保证每次循环之间无相关性。
- parallel for, parallel 和 for语句的结合,也是用在一个for循环之前,表示for循环的代码将被多个线程并行执行。
- sections,用在可能会被并行执行的代码段之前
- parallel sections,parallel和sections两个语句的结合
- critical,用在一段代码临界区之前
- single,用在一段只被单个线程执行的代码段之前,表示后面的代码段将被单线程执行。
- flush,
- barrier,用于并行区内代码的线程同步,所有线程执行到barrier时要停止,直到所有线程都执行到barrier时才继续往下执行。
- atomic,用于指定一块内存区域被制动更新
- master,用于指定一段代码块由主线程执行
- ordered, 用于指定并行区域的循环按顺序执行
- threadprivate, 用于指定一个变量是线程私有的。
- 来自TeddyZhang的总结
例1:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#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
例2:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <stdio.h>
#include <omp.h>
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());
}
输出:
i = 0, I am Thread 0
i = 1, I am Thread 0
i = 2, I am Thread 0
i = 0, I am Thread 2
i = 1, I am Thread 2
i = 2, I am Thread 2
i = 0, I am Thread 1
i = 1, I am Thread 1
i = 2, I am Thread 1
i = 0, I am Thread 3
i = 1, I am Thread 3
i = 2, I am Thread 3
例3:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <stdio.h>
#include "omp.h"
using namespace std;
int main() {
omp_set_num_threads(4);
#pragma omp parallel for
for (int i = 0; i < 10; i++)
printf("i = %d, I am Thread %d\n", i, omp_get_thread_num());
}
输出:
i = 0, I am Thread 0
i = 1, I am Thread 0
i = 2, I am Thread 0
i = 6, I am Thread 2
i = 7, I am Thread 2
i = 8, I am Thread 3
i = 9, I am Thread 3
i = 3, I am Thread 1
i = 4, I am Thread 1
i = 5, I am Thread 1
常用库函数
- omp_get_num_procs, 返回运行本线程的多处理机的处理器个数。
- omp_get_num_threads, 返回当前并行区域中的活动线程个数。
- omp_get_thread_num, 返回线程号
- omp_set_num_threads, 设置并行执行代码时的线程个数
- omp_init_lock, 初始化一个简单锁
- omp_set_lock, 上锁操作
- omp_unset_lock, 解锁操作,要和omp_set_lock函数配对使用。
- omp_destroy_lock, omp_init_lock函数的配对操作函数,关闭一个锁