OpenMP并行开发(C++)

https://zhuanlan.zhihu.com/p/51173703

最近,有个课设关于提取SIFT特征,老师要求不能使用OpenCV,从底层实现SIFT特征,在实现的过程中,参考了很多人的思路,其中有一个是对代码进行并行优化,引起了我的兴趣,所以找了一些资料来详细认识下OpenMP的使用~~

参考文章:

OpenMP并行程序设计(二) - 周伟明的多核、测试专栏 - CSDN博客​blog.csdn.net

标准并行模式执行代码的基本思想是,程序开始时只有一个主线程,程序中的串行部分都由主线程执行,并行的部分是通过派生其他线程来执行,但是如果并行部分没有结束时是不会执行串行部分的~

开发环境:VS2015,注意使用时要将OpenMP打开,并且#include "omp"

在C++中,OpenMP的指令格式为:#pragma omp指令[子句[子句]…]

例如: #pragma omp parallel private(i, j)

parallel 就是指令, private是子句

1. 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, 用于指定一个变量是线程私有的。

例子1:

#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;
	}
}

结果1:

Hello, I am Thread 1
Hello, I am Thread 0
Hello, I am Thread 2
Hello, I am Thread 3

例子2:(带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(); } 

结果2:

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

例子3:

#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();
}

结果3:

i = 0, I am Thread 0
i = 1, I am Thread 1
i = 2, I am Thread 2

注意注意:例子三和例子二的区别和不同

2. OpenMP的常用库函数

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函数的配对操作函数,关闭一个锁

如果在VS2015中运行时,首先要先做一个判断,编译器是否支持OpenMP,在下图中把其打开,然后在程序中做一个判断语句:

#ifdef _OPENMP //判断是否定义
omp_lock_t lock;
omp_init_lock(&lock);
#endif

设置打开OpenMP:

3. OpenMP的子句

private, 指定每个线程都有它自己的变量私有副本。

firstprivate,指定每个线程都有它自己的变量私有副本,并且变量要被继承主线程中的初值。

lastprivate,主要是用来指定将线程中的私有变量的值在并行处理结束后复制回主线程中的对应变量。

reduce,用来指定一个或多个变量是私有的,并且在并行处理结束后这些变量要执行指定的运算。

nowait,忽略指定中暗含的等待

num_threads,指定线程的个数

schedule,指定如何调度for循环迭代

shared,指定一个或多个变量为多个线程间的共享变量

ordered,用来指定for循环的执行要按顺序执行

copyprivate,用于single指令中的指定变量为多个线程的共享变量

copyin,用来指定一个threadprivate的变量的值要用主线程的值进行初始化。

default,用来指定并行处理区域内的变量的使用方式,缺省是shared

 

其实,实际中做优化时会考虑的更多更复杂,不过自己的代码优化的话,一般也就是优化for循环多一些,比较简单。具体使用时再进行查找深入了解~

猜你喜欢

转载自www.cnblogs.com/dhcn/p/12272898.html