OpenMP
OpenMP 共享内存并行
OpenMP 是单机多线程共享内存并行工具。
OpenMP 使用 fork-join 模型进行并行,即主线程通过 fork
创建多个并行线程,之后再将子线程 join
回主线程。
OpenMP API 由三部分组成
- 编译器指令
#pragma omp ...
- 运行时库函数
#include <omp.h>
- 环境变量
OMP_NUM_THREADS
等
参考资料
- llnl/openmp 的教程
编译器指令
编译器指令的格式为
#pragma omp |
指令名 | [clause, ...] |
换行 |
---|---|---|---|
所有OpenMP指令的开头 | 一系列可用的指令 | 可选的,从句顺序任意 | 换行不需要分号,可用用反斜线折行 |
#pragma omp parallel default(shared) private(beta, pi)
parallel 指令
创建一系列线程运行接下来的结构块,并在结构块结束时合并所有线程
可用的从句
if (scalar_expression)
-
private (list)
指定变量是私有的 shared (list)
default (share | none)
firstprivate (list)
copyin (list)
num_threads (integer-expression)
for 指令
指定接下来的循环迭代并行运行。
-
schedule (type [,chunk])
描述循环如何分配给线程 -
ordered
指定线程必须按照循环的顺序合并 private (list)
firstprivate (list)
lastprivate (list)
shared (list)
reduction (operator: list)
collapse (n)
-
nowait
循环结束后不等待未结束的线程
#pragma omp parallel shared(a,b,c,chunk) private(i)
{
#pragma omp for schedule(dynamic,chunk) nowait
for (i=0; i < N; i++)
c[i] = a[i] + b[i];
} /* end of parallel section */
sections, section 指令
外层用 sections
指令,内部用 section
指令
#pragma omp parallel shared(a,b,c,d) private(i)
{
#pragma omp sections nowait
{
#pragma omp section
for (i=0; i < N; i++)
c[i] = a[i] + b[i];
#pragma omp section
for (i=0; i < N; i++)
d[i] = a[i] * b[i];
} /* end of sections */
} /* end of parallel section */
single 指令
指定块内部同时只有一个线程运行,用来处理以下线程不安全的操作
task 指令
master 指令
指定只有主线程执行块内的程序。
critical 指令
指定同时只有一个线程能运行内部的代码。
#pragma omp parallel shared(x)
{
#pragma omp critical
x = x + 1;
} /* end of parallel section */
barrier 指令
要求所有线程立即同步
taskwait 指令
atomic 指令
执行原子操作,相当于小的 critical 指令
flush 指令
要求所有缓冲的修改写回内存中
下面一些指令隐含了 flush
指令
barrier
-
parallel
的进和出 -
critical
的进和出 -
ordered
的进和出 -
for
的出 -
sections
的出 -
single
的出
ordered 指令
要求代码块内部的指令顺序执行,只能用在 for
指令内部
threadprivate 指令
指定一些变量是线程私有的,每个线程初次使用这些变量时都是未初始化的
reduction 从句
要求循环分成相等的部分,并在全部运行最后再执行指定的指令
支持的格式
x = x op expr
x = expr op x
x binop = expr
x++
++x
x--
--x
op: +, *, -, /, &, ^, &&, ||
binop: +, *, -, /, &, ^, |
例子
#pragma omp parallel for \
default(shared) private(i) \
schedule(static,chunk) \
reduction(+:result)
for (i=0; i < n; i++)
result = result + (a[i] * b[i]);
运行时库函数
线程环境相关
函数 | 作用 |
---|---|
omp_set_num_threads() |
设置使用的线程数 |
omp_get_num_threads() |
获取使用的线程数 |
omp_get_max_threads() |
获取可用最大的线程数 |
omp_get_thread_num() |
获取线程编号 |
omp_get_thread_limit() |
获取最大可用线程 |
omp_get_num_procs() |
获取处理器数目 |
锁
函数 | 作用 |
---|---|
omp_init_lock() |
初始化锁 |
omp_destroy_lock() |
删除锁 |
omp_set_lock() |
加锁 |
omp_unset_lock() |
解锁 |
omp_test_lock() |
测试加锁 |
omp_init_nest_lock() |
初始化嵌套锁 |
omp_destroy_nest_lock() |
删除嵌套锁 |
omp_set_nest_lock() |
加嵌套锁 |
omp_unset_nest_lock() |
解嵌套锁 |
omp_test_nest_lock() |
测试加嵌套锁 |
说明:
- OpenMP 的锁是互斥锁,即 mutex
-
与
critical
指令的区别是,critical
指令保证同时只有一个线程运行内部的指令,而不是加锁例子:
#include <omp.h> omp_lock_t lock; omp_init_lock(&lock); int i = 0; #pragma omp parallel { while(true){ omp_set_lock(&lock); x++; omp_unset_lock(&lock); break; } } omp_destroy_lock(&lock);
环境变量
变量 | 作用 |
---|---|
OMP_SCHEDULE |
for 指令的默认从句 |
OMP_NUM_THREADS |
使用的最大线程数 |
OMP_NESTED |
是否使用嵌套并行 |
OMP_STACKSIZE |
设置子线程的栈大小 |
OMP_WAIT_POLICY |
设置等待线程的行为 |
OMP_MAX_ACTIVE_LEVELS |
设置嵌套并行的层级 |
OMP_THREAD_LIMIT |
设置整个程序的最大线程数 |
评论
Comments powered by Disqus