编译命令:gcc –O XXX.c -fopenmp
1. Multi-thread Programming
1. 首先要import相应的API,因此必须在首行写上#include “omp.h”。
2. 对于要并行执行的部分,用#pragma omp parallel{…} 标记并行块范围。
3. 在并行块里面,用int ID = omp_get_thread_num(); 来获取并行线程的ID。注意:Master thread的ID为0。
4. 设定并行线程的数目的方式有两种:1. 如果要设定并行线程的数目在并行块外,调用omp_set_num_threads(intnum)函数。2.也可以在声明并行块的时候同时声明设定并行线程的数目,即使用#pragma omp parallelnum_threads(int num){}代替#pragma omp parallel{ }。如果不设定并行线程的数目,则并行线程数目的缺省值为CUP的核数。
5. 在并行块内,一般会使用int nthrds = omp_get_num_threads()来获得并行线程的总数,这样方便在遍历的时候设立stride。
2. Synchronization
2.1 critical
在并行块中的关键区域上锁,实行局部的串行操作。
#pragma omp critical{ …}
2.2 atomic
作用同critical,但是仅对某个内存区域的读写操作有效(e.g.如果要调用某个函数,可能就会失效),速度比critical更快。
#pragma omp atomic{ …}
3. Parallel Loops
3.1自动并行执行for循环(循环子默认为private)
#pragma omp for{ …}
e.g.
#pragma omp parallel for
for(i = 0; i<N;i++)
a[i] = a[i] + b[i];
等效于
#pragma omp parallel
{
intid, i, Nthrds, istart, iend;
id= omp_get_thread_num();
Nthrds= omp_get_num_threads();
istart= id * N / Nthrds;
iend= (id + 1)* N / Nthrds;
for(i=istart;i<iend; i++){
a[i] = a[i] + b[i];
}
}
本质上就是把循环子i的遍历空间进行划分,让每个线程包办一部分的iterations,iteration次数尽量做到平均。前提是不存在依赖!
注:如果标记块中仅含有一个statement,则#pragma ompfor后的大括号可以去掉。如果整个并行块里面只有一个for循环,则可以将声明并行块的#pragma omp parallel{ …}与并行块里面的#pragma omp for{…}简写成#pragma omp parrellel for{ …}
此外,用并行for循环优化时,注意要去掉loop carried dependence,e.g.
int i, j, A[MAX];
j = 5;
for(i=0;i<MAX;i++){
j +=2;
A[j] = big(j);
}
改为
int i, j, A[MAX];
#pragma omp parallel for{
for(i=0;i<MAX;i++){
int j = 5 + 2i;
A[j] = big(j);
}
实质是将并行块外定义的用j的递推公式表示的线程共享变量,替换为并行块内定义的用i的通项公式表示的线程私有变量。
3.2自动并行执行reduction
reduction (op:list)