基础

OpenMP是一种面向共享内存以及分布式共享内存的多处理器多线程并行编程模型。它支持c++, c, Fortran语言。

它在最开始的时候只有主线程,在需要的时候又可以分出多个线程进行计算,计算完毕之后又可以变成一个线程。

它的头文件是omp.h

一个例子:

#include <omp.h>
int main()
{
double res[1000];
#pragma omp parallel for
for(int i=0; i<1000; i++)
{
do_huge_comp(res[i]);
}
}

编译制导语句

同步与作用域

  • #pragma omp master: 表明该区域只能由主线程执行
  • #pragma omp critical (name): 临界区,一次只能由一个线程执行
  • #pragma omp barrier: 用来同步所有线程,先到达的会等待,直到所有线程到达
  • #pragma omp atomic: 表明该语句是原子指令
  • #pragma omp flush(list): flush用来同步内存,他会在如for退出或进入critical区域时隐含执行,使用nowait除外
  • #pragma omp ordered: 将让循环在这片区域内按次序进行
  • private: 线程在这片区域内私有,并且会自动初始为0
  • shared: 所有线程共享。使用并行区域外部的变量时默认是共享的
  • default: 确定变量在并行域的初始值
  • firstprivate: 私有变量的初始值是外部变量的值
  • lastprivate: 将最后的私有变量的值赋给全局变量(也就是主线程的)
  • reduction: 在sections中讲了
  • threadprivate: 这是线程在进程整个生命周期中都拥有的变量,一般写在main前面。例如一个变量声明为threadprivate,在一个parallel语句内部改变了,在下一个parallel语句中使用改变了的值
  • copyin: 为线程中所有threadprivate变量赋相同的值(可以使用外部的变量进行赋值)

并行域

并行域表示在并行域中的代码将会由多个线程执行

格式:

#pragma omp parallel [clause...]

clause =
if()
private(): 表明变量在这个并行区域内是线程私有的
firstprivate()
default(shared | none)
shared()
copyin()
reduction()
num_threads(): 指开启的线程数

例如:
int nthreads, tid;
# pargma omp parallel private(tid)
{
tid = omp_get_thread_num();
printf("Hello thread=%d\n", tid);
if(tid == 0)
{
nthreads = omp_get_num_threads();
printf("num of threads = %d\n", nthreads);
}
}

for语句

for语句指定它后面的for将会由线程组执行。但是它只可以并行化执行for循环,而不会执行while循环。实际上如果中间有break也不能用for语句

格式:
#pragma omp for [clause]

clause:
Schedule(type[, chunk]): chunk表示一个线程每次会得到多少循环次数.type有static
dynamicstatic是按照chunk预先分配,dynamic是执行完这个chunk向系统再要一
chunk
ordered
lastprivate()
nowait
上面的除了default, copyin, num_threads()

Sections语句

Sections语句规定每个线程完成不同任务

格式:

#pragma omp sections [clause..]
{
#pragma omp section
{
...
}

#pragma omp section
{
...
}
...
}

clause:

* private()
* firstprivate()
* lastprivate()
* reduction(operator: list): reduction内的变量时区域私有变量(也就是说不用加private了),并且reduction在每个线程结束时将私有变量进行运算。例如: reduction(+: ans)就是将每个线程的ans私有变量相加,然后赋值给全局ans
* nowait

single语句

single指名该区域只能有一个线程执行。线程组中没有执行single语句会等待内部线程结束,使用nowait除外。