前言
OpenMP(Open Multi-Processing)是一套支持跨平台共享内存方式的多线程并发的编程API,使用C,C++和Fortran语言,可以在大多数的处理器体系和操作系统中运行,包括Solaris, AIX, HP-UX, GNU/Linux, Mac OS X, 和Microsoft Windows。
它通过以指定语法声明块的形式使块内代码或并行或原子,十分方便。
CLion配置OpenMP
从IDEA入坑开始,一直喜欢JetBrain公司的IDE,所以这里只介绍在CLion下如何配置OpenMP环境。
1、CMakeLists下添加如下代码:
1 2 3 4 5 6 7 8 9 10 11
| cmake_minimum_required(VERSION 3.10) project(untitled1)
set(CMAKE_CXX_STANDARD 11) FIND_PACKAGE( OpenMP REQUIRED) if(OPENMP_FOUND) message("OPENMP FOUND") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") endif() add_executable(untitled1 main.cpp)
|
2、然后在需要使用的代码中添加头文件
完成这两步后,我们就可以愉快的使用了
教程
并行区域
如果我们需要指定一个区域的代码是需要并行操作的,只需要通过如果下格式声明即可
1 2 3 4 5 6
| #pragma omp parallel {
}
|
这一代码块可以嵌入到任意一个我们需要并行的函数中,比如
1 2 3 4 5 6 7
| int main(){ #pragma omp parallel { printf("now in thread %d\n", omp_get_thread_num()); } }
|
输出结果如下
1 2 3 4 5 6 7 8
| now in thread 1 now in thread 6 now in thread 2 now in thread 7 now in thread 4 now in thread 3 now in thread 0 now in thread 5
|
这里的结果和运行代码的机器核心数有关,因为openmp默认启用核心数匹配的线程数。而我电脑是八核的,所以这里有八个线程。
线程数控制
OpenMP有两种控制线程的方式,一是通过在并行区域前通过omp_set_num_threads()
函数设置,二是通过并行区参数设置,分别如下
1 2 3 4 5 6 7
| int main(){ omp_set_num_threads(4); #pragma omp parallel { printf("now in thread %d\n", omp_get_thread_num()); } }
|
上面这种形式和下面这一方式等价
1 2 3 4 5 6
| int main(){ #pragma omp parallel num_threads(4) { printf("now in thread %d\n", omp_get_thread_num()); } }
|
共享变量和私有变量
如果未特殊声明,在#pragma omp parallel
内部定义的为私有变量,反之为共享变量。
但我们可以通过shared(item-list) praivate(item-list)
等语句更改变量属性,如下:
1 2 3 4 5 6 7 8
| int a,b,c,d; #pragma omp parallel shared(a,b,c) private(d) {
printf("now in thread %d\n", omp_get_thread_num()); }
|
for指令
指令for
标识一个迭代工作共享构造,该构造指定将并行执行关联循环的迭代。指令如下:
1 2 3 4 5
| #pragma omp for for (int i = 0; i < count; ++i) { }
|
值得一提的是,这里的i
是私有变量。这段代码的意思是,开启数量为count
的并行线程,每个线程都执行for循环内的代码块。
critical
critical的语义是指在任意时刻只有最多一个线程在执行临界区的代码。
用法
1 2 3 4
| #pragma omp critical [(name)] { <临界区代码> }
|
锁
在OpenMP中,锁分两种:普通锁和嵌套锁。
普通锁用于单层并行结构,即子线程不会新开并行线程。用 omp_lock_t
声明
嵌套锁用于嵌套并行结构,即子线程中可能还会新开线程。用 opm_nest_lock_t
声明
声明锁
1 2
| omp_lock_t ompLock; omp_nest_lock_t ompLock;
|
初始化锁
1 2 3
| #include <omp.h> void omp_init_lock(omp_lock_t *lock); void omp_init_nest_lock(omp_nest_lock_t *lock);
|
获取锁
1 2 3
| #include <omp.h> void omp_set_lock(omp_lock_t *lock); void omp_set_nest_lock(omp_nest_lock_t *lock);
|
释放锁
1 2 3
| #include <omp.h> void omp_unset_lock(omp_lock_t *lock); void omp_unset_nest_lock(omp_nest_lock_t *lock);
|
销毁锁
1 2 3
| #include <omp.h> void omp_destroy_lock(omp_lock_t *lock); void omp_destroy_nest_lock(omp_nest_lock_t *lock);
|
测试锁
如下两个函数尝试设置锁,但不阻止线程的执行。其格式如下:
1 2 3
| #include <omp.h> int omp_test_lock(omp_lock_t *lock); int omp_test_nest_lock(omp_nest_lock_t *lock);
|