配置
正常现代编译器都支持OpenMP,以gcc为例只要添加-fopenmp参数就可启用openmp:1
g++ test.cpp -fopenmp
在程序中检测是否开启openmp1
2
3
std::cerr << "OpenMP not supported" << std::endl;
简单使用
只需要在for循环之前加上一句pragma就可实现并行化:1
2
3
4
for (int i = 0; i < 100; ++i) {
// do something
}
但对循环有五个要求否则编译将不通过:
- 循环变量必须是int
- 循环判断条件必须是<,> <=, >=
- 循环增量固定
- 如果比较符号为<,<=,则循环增量为正,反之亦然
- break、异常等只能在循环内部,总之程序执行流程不能跳出并行的for循环
除此之外,不同迭代之间的数据不应该存在依赖。
公有和私有数据
for循环内定义的数据为openmp线程私有的数据,循环外为线程共享的数据。1
2
3
4
5
6int g_val = -1;
for (int i = 0; i < 100; ++i) {
cout << g_val << endl;
}
cout << g_val << endl;
上述程序中,通过private(g_val)将共有数据g_val私有化,具体地,每个线程都定义了一个g_val,并且未被初始化,所以循环内输出结果不等于-1,每个线程内的g_val与外部g_val无关。1
pragma omp parrallel for firstprivate(g_val)
firstprivate与private的区别在于每个线程的g_val会使用公有的g_val的初始化。1
pragma omp parrallel for lastprivate(g_val)
lastprivate会使用最后一次for循环迭代的g_val赋值给公有的g_val。
Reduction
1 | int sum = 0; |
上述程序中,openmp为每个线程定义了私有变量sum,并初始化为0,当线程退出时,会把每个线程内sum的值累加在一起赋值给循环外的sum。
Schedule
openmp使用下述语法配置线程调度:1
pragma omp parallel for schedule(kind [, size])
其中kind是调度类型,有static, dynamic, guided, runtime(由环境变量OMP_SCHEDULE来确定调度类型),size表示分配给线程的size次连续的迭代计算。