并行与分布式计算:OpenMP的语法概览
OpenMP的语句
这一章作为一个概览式的指导存在,如果编程能力不够强,不能理解这里面简略言及的效果,建议参考第五章
头文件
#include<omp.h>
库函数
int omp_get_num_procs(void);//获取当前可用的物理处理器总数目
int omp_get_thread_num(void);//获取当前线程id
void omp_set_num_threads(int t);//设置程序中激活的线程数
指导句X #progma omp X
parallel
标记代码块为并行域,并行域中的所有代码若无特殊标记都要被所有线程执行
for
(一般在并行域中使用)将紧邻的下一个for循环所有计算内容按迭代器平均分配给每一个线程
parallel for
标记下方for循环为并行域并将所有内容按迭代器均分给每一个线程
critical
(一般在并行域中使用)标记代码块在同一时刻只能由一个线程进行执行(但所有线程最终都会跑一遍这部分代码)
master
(一般在并行域中使用)指定下方代码块为仅主线程执行的代码
(可以用于IO等并行容易出错的地方)
single
(一般在并行域中使用)指定下方代码块仅由一个线程执行,其他所有线程将等待该线程完成任务
(可以用于IO等并行容易出错的地方)
single nowait
告知其他线程不必等待该线程完成即可自行向下继续任务
barrier
(一般在并行域中使用)设置路障,线程组中的所有线程在此同步(只有所有线程都抵达此处后,才准许线程进行后续的任务)
(路障可以用于后续的任务与前面各个线程的结果都有依赖关系时)
task
在一个线程中产生一个新的task并由一个子线程接手处理
taskwait
设置路障,一个线程的所有子线程在此同步(只有所有子线程都完成了自己先前的任务并到达此处时才准许执行后面的任务)
指导句子句Y #pragma omp X Y
shared([varibleList])
适用指导语:parallel/for/parallel for
效果:括号内变量被所有线程共享(注意,这将增加耗时)
private([varibleList])
适用指导语:parallel/for/parallel for
效果:括号内变量为各个线程私有(这在一定程度上与在线程内声明变量的效果相似)
注意:即使在之前被声明私有的变量已经被赋值了,每个线程也不会采取那个值。所以私有变量在线程内都未初始化,必须重新赋值。同时,当并行区域结束时,原变量的值也不会因为在某个线程处被重新赋值而改变。
reduction(operatorX:varibleY)
适用指导语:for/parallel for
效果:在各个线程内用与操作符X相符的初始值初始化Y(如操作符+对应的初始值为0,操作符*对应的初始值为1),然后在各个线程内各自进行累X操作(例如累加、累乘),最后再把各线程的结果和Y实际上的初始值累X到一起(从累加的角度看,就是各线程内部求和,将结果赋给线程内形式的Y,再把各个线程的结果进行求和操作,最后把结果X给实际的Y)
举例:
sum=1;
#pragma omp parallel for reduction(+:sum)
for(int i=1;i<=100;i++)
{
sum+=i;//每个线程内,sum以0为初值,对自己分到的迭代器做累加
}
//执行完毕后,所有线程的sum进行求和,并加到sum的初始值上
cout<<sum<<endl;//sum=1+1+2+3+...+100
nowait
适用指导语:single
效果:其他线程不再等待该线程任务完成
schedule(kind,chunkSize)
适用指导语:for/parallel for
效果:手动分配迭代器
详解:
- 静态调度 static
- 0 - chunkSize-1分配给第一个线程chunkSize - 2chunkSize-1分配给第二个线程,以此类推
- 不填size默认为平均分配(size=迭代数/线程数上取整)
- 动态调度 dynamic
- 每次都将chunkSize个迭代器分配给一个可用线程
- 也就是线程空闲时会自动取领取一个chunkSize大小的任务
- 由于线程的启动时机和执行完的时间不确定,所以迭代器被分配到哪个线程时无法事先知道的
- 不填size默认为1
- 启发式调度 guided
- chunkSize表示每次分配的迭代次数的最小值
- 每次分配给线程的迭代次数是不同的,开始可能比较大,以后逐渐减小
- 是一种更灵活的动态分配,当有大量任务时就会一次性分配较多任务,从而使得分配消耗更少,执行效率更高;当任务量较少时一次性分配较少线程,从而使得负载更加均衡
- 不填size默认为1