openmp入门 for循环并行化的约束条件 redcution工具 critical工具实例 sections工具 API示例

编译flag: -fopenmp
头文件:#include "omp.h"
代码中使用标识 :#pragma omp parallel


for循环并行化的约束条件

尽管OpenMP可以方便地对for循环进行并行化,但并不是所有的for循环都可以进行并行化。以下几种情况不能进行并行化:

  1. for循环中的循环变量必须是有符号整形。例如,for (unsigned int i = 0; i < 10; ++i){}会编译不通过;
  2. for循环中比较操作符必须是<, <=, >, >=。例如for (int i = 0; i != 10; ++i){}会编译不通过;
  3. for循环中的第三个表达式,必须是整数的加减,并且加减的值必须是一个循环不变量。例如for (int i = 0;i != 10;i = i + 1){}会编译不通过;感觉只能++i; i++; --i;i--;
  4. 如果for循环中的比较操作为<<=,那么循环变量只能增加;反之亦然。例如for (int i = 0; i != 10; --i)会编译不通过;
  5. 循环必须是单入口、单出口,也就是说循环内部不允许能够达到循环以外的跳转语句,exit除外。异常的处理也必须在循环体内处理。例如:若循环体内的breakgoto会跳转到循环体外,那么会编译不通过。

redcution工具

#pragma omp parallel for reduction(+:sum)
reduction虽然很方便,但它只支持一些基本操作,比如+,-,*,&,|,&&,||等。有些情况下,我们既要避免race condition,但涉及到的操作又超出了reduction的能力范围,应该怎么办呢?这就要用到openMP的另一个工具,critical。来看下面的例子,该例中我们求数组a的最大值,将结果保存在max里。


critical工具实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
int main()
{
int max = 0;
int a[10] = {11,2,33,49,113,20,321,250,689,16};
#pragma omp parallel for
for(int i=0;i<10;i++)
{
int temp = a[i];
#pragma omp critical
{
if(temp > max)
max = temp;
}
}
std::cout<<"max: "<<max<<std::endl;
return 0;
}

上例中,for循环还是被自动分成N份来并行执行,但我们用#pragma omp criticalif (temp > max) max = temp括了起来,它的意思是:各个线程还是并行执行for里面的语句,但当你们执行到critical里面时,要注意有没有其他线程正在里面执行,如果有的话,要等其他线程执行完再进去执行。这样就避免了race condition问题,但显而易见,它的执行速度会变低,因为可能存在线程等待的情况。


sections工具

1
2
3
4
5
6
7
8
9
10
11
#pragma omp parallel sections
{
#pragma omp section
{
function1();
}
#pragma omp section
{
function2();
}
}

parallel sections里面的内容要并行执行,具体分工上,每个线程执行其中的一个section,如果section数大于线程数,那么就等某线程执行完它的section后,再继续执行剩下的section。在时间上,这种方式与人为用vector构造for循环的方式差不多,但无疑该种方式更方便,而且在单核机器上或没有开启openMP的编译器上,该种方式不需任何改动即可正确编译,并按照单核串行方式执行。


API示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// 设置并行线程数
_OMPIMP void _OMPAPI omp_set_num_threads(int _Num_threads);
// 获取当前并行线程数
_OMPIMP int _OMPAPI omp_get_num_threads(void);
// 获取当前系统最大可并行运行的线程数
_OMPIMP int _OMPAPI omp_get_max_threads(void);
// 获取当前运行线程的ID,注意和操作系统中的线程ID不同
_OMPIMP int _OMPAPI omp_get_thread_num(void);
// 获取当前系统中处理器数目
_OMPIMP int _OMPAPI omp_get_num_procs(void);
_OMPIMP void _OMPAPI omp_set_dynamic(int _Dynamic_threads);
_OMPIMP int _OMPAPI omp_get_dynamic(void);
_OMPIMP int _OMPAPI omp_in_parallel(void);
_OMPIMP void _OMPAPI omp_set_nested(int _Nested);
_OMPIMP int _OMPAPI omp_get_nested(void);
_OMPIMP void _OMPAPI omp_init_lock(omp_lock_t * _Lock);
_OMPIMP void _OMPAPI omp_destroy_lock(omp_lock_t * _Lock);
_OMPIMP void _OMPAPI omp_set_lock(omp_lock_t * _Lock);
_OMPIMP void _OMPAPI omp_unset_lock(omp_lock_t * _Lock);
_OMPIMP int _OMPAPI omp_test_lock(omp_lock_t * _Lock);
_OMPIMP void _OMPAPI omp_init_nest_lock(omp_nest_lock_t * _Lock);
_OMPIMP void _OMPAPI omp_destroy_nest_lock(omp_nest_lock_t * _Lock);
_OMPIMP void _OMPAPI omp_set_nest_lock(omp_nest_lock_t * _Lock);
_OMPIMP void _OMPAPI omp_unset_nest_lock(omp_nest_lock_t * _Lock);
_OMPIMP int _OMPAPI omp_test_nest_lock(omp_nest_lock_t * _Lock);
_OMPIMP double _OMPAPI omp_get_wtime(void);
_OMPIMP double _OMPAPI omp_get_wtick(void);