0%

OpenMP从配置到使用

前言

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
#include "omp.h"

完成这两步后,我们就可以愉快的使用了

教程

并行区域

如果我们需要指定一个区域的代码是需要并行操作的,只需要通过如果下格式声明即可

1
2
3
4
5
6
#pragma omp parallel 
{
/*
* 这里是需要并行操作的代码块
*/
}

这一代码块可以嵌入到任意一个我们需要并行的函数中,比如

1
2
3
4
5
6
7
int main(){
#pragma omp parallel
{
// omp_get_thread_num() 返回线程团队内执行的线程的线程号。
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)
{
/*
* 在这里,abc是共享变量,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)
{
/* code */
}

值得一提的是,这里的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); //如果成功设置锁,则返回非0值;失败则返回0值
int omp_test_nest_lock(omp_nest_lock_t *lock); //如果成功设置锁,则返回新的嵌套计数;失败则返回0值
-------------------本文结束 感谢阅读-------------------
  • 本文作者: CeaserBorgia
  • 本文链接: https://timegoesby.top/OpenMP/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!