OpenMP并行程序
1.fork/join 并行执行模式
标准并行模式执行代码的基本流程是:程序开始时只有一个主线程,程序中的串行部分都由主线程执行,并行的部分通过派生其他的线程来执行,但是如果并行部分没有结束时是不会执行串行部分的。比如:
int main()
{
clock_t t1=clock();
#pragma omp parallel for
for(int i=0;i<1000;i++)
{
cout<<i<<endl;
}
//在前面的并行计算执行完毕之前,是不会执行下面的串行代码的
clock_t t2=clock();
cout<<"Time is:"<<t2-t1<<endl;
}
对于主线程而言,是创建了派生线程,然后等待派生线程执行完毕。这种并行模式就是标准的fork/join模式。主线程并没有和派生线程并行运行。
2. openMP指令和库函数
在C/C++当中,openMP的指令格式是:
#pragma omp 指令 [子句] [子句]…
比如 parallel for 就是一条指令。例如:
#pragma omp parallel private(i,j) // parallel 就是指令,private 是子句
2.1 openMP的指令有以下:
parallel, 用在一个代码段之前,表示这段代码将被多个线程并行执行;
for 用在for循环之前,将循环分配到多个线程并行执行,必须保证每次循环之间无相关性;
parallel for, parallel 和for的结合,也是用在for循环之前,表示循环的代码将被多个线程并行执行;
sections,用在可能会被并行执行的代码段之前;
parallel sections, parallel 和sections两个语句的结合;
critical, 用在一段代码临界区之前。注:临界区指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性。当有线程进入临界区段时,其他线程或是进程必须等待。比如一台打印机。
single, 用在一段只被单个线程执行的代码段之前,表示后面的代码将被单线程执行;
barrier, 用于并行区内代码的线程同步,所有线程执行到barrier时要停止,直到所有线程都执行到barrier时才继续往下执行;
atomic, 用于指定一块内存区域被自动更新;
master, 用于指定一段代码块由主线程执行;
ordered,用于指定并行区域的循环按顺序执行;
threadprivate, 用于指定一个变量是线程私有的。
2.2.除了上述指令之外,还有一些库函数,以下是常用的:
omp_get_num_procs, 返回运行本线程的多处理机的处理器个数;
omp_get_num_threads, 返回当前并行区域中的活动线程个数;
omp_get_thread_num, 返回线程号;
omp_set_num_threads, 设置并行执行代码时的线程个数;
omp_init_lock, 初始化一个简单锁;
omp_set_lock, 上锁操作;
omp_unset_lock, 解锁操作,和omp_set_lock函数配对使用;
omp_destory_lock,omp_init_lock函数的配对操作函数,关闭一个锁。
2.3.OpenMP的子句有以下一些:
private, 指定每个线程都有它自己的变量私有副本;比如:#pragma omp parallel private(i,j) 将指定线程拥有私有副本变量i,j。
firstprivate, 指定每个线程都有它自己的变量私有副本,且变量要被继承主线程中的初值;
lastprivate,主要是用来指定将线程中的私有变量的值在并行处理结束后复制回主线程中的对应变量;
reduce,用来指定一个或多个变量是私有的,并且在并行处理结束后这些变量要执行指定的运算;
nowait,忽略指定中暗含的等待;
num_threads,指定线程的个数;
schedule,指定如何调度for循环迭代;
shared,指定一个或多个变量为多个线程间的共享变量;
ordered, 指定for循环的执行要按顺序执行;
copyprivate, 用于single指令中的指定变量为多个线程的共享变量;
copyin,用来指定一个threadprivate的变量的值要用主线程的值进行初始化;
default,用来指定并行处理区域内的变量的使用方式,缺省是shared。
parallel是用来构造一个并行块的,也可以使用其他指令如for、sections等和它配合使用。
在c/c++当中,parallel的使用方法如下:
#pragma omp parallel [for| sections][子句][子句...]
{
代码
}
// parallel语句后面要跟一个大括号对将要并行执行的代码括起来,如:
#pragma omp parallel num_threads(8) //指定8个线程执行括号内代码
{
cout<<"hello,world!"<<endl; //会输出八次
}
2.4.for指令的使用
for指令是用来将一个for循环分配到多个线程中执行,for指令一般与parallel指令合起来形成parallel for 指令使用,也可以单独用在parallel语句的并行块中。
#pragma omp [parallel] for [子句]
for循环语句
单独使用for,而没有parallel时,是没有效果的。
一个parallel块中也可以有多个for语句,例如:
#pragma omp parallel
{
#pragma omp for
for(int i=0;i<10;i++){...} //for循环语句必须按照三条小语句的规范书写
#pragma omp for
for(int j=0;j<10;j++){...}
}
2.5.sections和section指令的用法
section语句是用在sections语句中,用来将sections语句内的代码划分成不同的段,每段都并行执行,用法如下:
#pragma omp [parallel] sections [子句]
{
#pragma omp section
{
代码块1
}
#pragma omp section
{
代码块2
}
...
}
注:使用section语句时,需要注意的是这种方式需要保证各个section里的代码执行时间相差不大,否则某个section执行时间比其他section过长就达不到并行执行的效果了。
当然,也可以写成:
#pragma omp parallel
{
#pragma omp sections
{
#pragma omp section
{
代码块1
}
#pragma omp section
{
代码块2
}
}
#pragma omp sections
{
#pragma omp section
{
代码块3
}
#pragma omp section
{
代码块4
}
}
}
这种情况下,两个sections语句是串行执行的,第二个sections语句内的代码要等到第一个sections语句内的代码执行完之后才能执行。
以上文字内容转载自:
https://blog.csdn.net/drzhouweiming/article/details/1175848