OpenMP并行加速

OpenMP并行加速

1.   简介

OpenMP是一个编译器指令和库函数集合,主要是为共享式存储计算机并行程序设计使用的。

OpenMP的一个Parallelfor指令,就是标准的并行模式fork/join式并行模式,基本思想是,程序开始时只有一个主线程,程序中的串行部分都由主线程执行,并行的部分是通过派生其他线程来执行,但是如果并行部分没有结束时是不会执行串行部分的。也即OpenMP并行执行的程序要全部结束后才能执行后面的非并行部分。

 

2.   调用形式:#pragma omp 指令 【子句【子句】…】

#pragma omp parallel  

          {  

            每个线程都会执行大括号里的代码,线程id号不确定

           }

带有for语句:将for循环拆分开来尽可能平均地分配到各个线程执行,要求数据不存在依赖。

1#pragma omp parallel for 

         for() 

作用域只是紧跟着的那个for循环,紧跟着的for变成并行,要求里面的循环互不干扰。

#pragma ompparallel for

         for (int i = 0; i < 6; i++)

                   printf("i = %d, I amThread %d\n", i, omp_get_thread_num());

         //这里是两个for循环之间的代码,将会由线程0即主线程执行

         printf("I am Thread %d\n", omp_get_thread_num());

#pragma ompparallel for

         for (int i = 0; i < 6; i++)

                   printf("i = %d, I amThread %d\n", i, omp_get_thread_num());

注意:两个for循环之间有一些代码只能有一个线程执行

 

2#pragma omp parallel 

         { //注意:大括号必须要另起一行  

         #pragma omp for 

          for() 

        }

整个并行块中可以出现多个for指令

#pragma ompparallel

         {

#pragma omp for

                   for (int i = 0; i < 6;i++)

                            printf("i = %d,I am Thread %d\n", i, omp_get_thread_num());

#pragma omp master

                   {

                            //这里的代码由主线程执行,改成single是随机选一个线程执行

                            printf("I amThread %d\n", omp_get_thread_num());

                   }

#pragma omp for

                   for (int i = 0; i < 6;i++)

                            printf("i = %d,I am Thread %d\n", i, omp_get_thread_num());

         }

for循环是一个一个平均分配给各个线程

 

指定执行的线程数

#pragma ompparallel num_threads(8)

{//花括号需换行

}

不同段并行执行

#pragma ompparallel sections

{    //需要保证各section里的代码执行时间相差不大

 #pragma omp section

{

}

}

omp_get_num_procs()函数来获取处理器个数,用omp_get_thread_num()函数来获得每个线程的ID,为了使用这两个函数,我们需要include

 

3.数据同步

(默认情况下sum变量是每个线程共享的,所以多个线程同时对sum操作时就会因为数据同步问题导致结果不对)

主要有循环里涉及到求和,或者求最大值的。

1)求和

#pragmaomp for reduction(+:sum)//归约(reduction),它只支持一些基本操作,比如+,-,*,&,|,&&,||

       for(int i = 0; i < n; i++) {

                            sum+= 1;

}// 每个线程拷贝一份sum变量,退出并行块时再把各个线程的sum相加

或者

#pragma omp parallel{

#pragma omp for

              for(int i = 0; i < n; i++) {

                     {

#pragmaomp critical

                            sum+= 1;

                     }

              }

       }

       cout<< " sum = " << sum << endl;

2)求最大值

#pragma omp parallel for

 for(int i=0;i<10;i++)

 {

  inttemp = a[i];

  #pragma omp critical//执行到critical里面时,要注意有没有其他线程正在里面执行,如果有的话,要等其他线程执行完再进去执行。  比较慢

  if(temp > max)

  max= temp; 

 }

3)用类似于互斥量的机制进行私有化和同步,可以消除数据竞争。

 #pragma omp parallel for private(x)

      for(i=0;i<80;i++)

       {

         x=sin(i);

         if(x>0.6)x=0.6;

         printf("sin(%d)=%f\n",i,x);

       }

 

4.其他语句

schedule语句(把循环一块一块分配给线程)

#pragma omp parallel

       {

#pragma omp for schedule(static, 3)

//每一块大小为3,然后再平均分配给各个线程执行。

              for(int i = 0; i < 12; i++) {

                     {

                            printf("i= %d, I am Thread %d\n", i, omp_get_thread_num());

                     }

              }

       }

结果:线程0执行i=0 1 2,线程1执行i=3 4 5,线程2执行i=6 7 8,线程3执行i=9 1011,如果后面还有则又从线程0开始分配。先后顺序不一定。

 

schedule的类型一共是三种:staticdynamicguided

a. 静态:OpenMP会给每个线程分配size次迭代计算。这个分配跟实际的运行无关,可以从逻辑上推断出哪几次迭代会在哪几个线程上运行。各个线程的任务是固定的,但是可能有的快,有的慢,不能达到最优。

b.动态:谁有空,给谁分配一次迭代让它去跑。每个线程按先执行完先分配的方式执行1次循环(有size参数就先执行size次)。根据线程的执行快慢,已经完成任务的线程会自动请求新的任务或者任务块,每次领取的任务块是固定的。

C,类似于动态调度,但每次分配的循环次数不同,开始比较大,以后逐渐减小。size表示每次分配的迭代次数的最小值,由于每次分配的迭代次数会逐渐减少,较少到size时,将不再减少。每个任务分配的任务是先大后小,指数下降。当有大量任务需要循环时,刚开始为线程分配大量任务,最后任务不多时,给每个线程少量任务,可以达到线程任务均衡。

 

语句barrier,用它可以在并行块中设置一个路障,必须等待所有线程到达时才能通过,这个一般在并行处理循环前后存在依赖的任务时使用到 。

私有变量privatefirstprivatelastprivatethreadprivate的使用:

http://syyming.blog.163.com/blog/static/2320635201082434535924/

OpenMP其他语句:http://blog.csdn.net/drzhouweiming/article/details/1175848

 

5. 实际操作中发现的问题

1.    其实只要会使用基本的#pragma omp parallelfor就可以了,要注意变量的定义(若循环中的该变量一直在变,则把定义放在循环内,即每个循环都创建一次)。

2.    需要并行的for循环的终止条件不能用!=

3.    error C3037: “reduction”子句中的变量必须在封闭上下文中共享

GetSaliencyMap

 

4.    涉及并行的中断

http://blog.csdn.net/yongh701/article/details/51395628

要求在i=100时退出,【for(inti=0;i<200&&(i!=0&&i%100==0);i++) 会显示errorC3017: OpenMP“for”语句中的终止测试格式不正确。】

需添加标志位;

bool finish_flag=false; 

#pragma omp parallel fornum_threads(4) 

for(i=0;i<200;i++){ 

       if(finish_flag==true){ 

           continue; 

       } 

       if(finish_flag==false){ 

           if(i!=0&&i%100==0){ 

                result=i; 

                finish_flag=true; 

          } 

      } 

   } 

   cout<

 

 

 

并发与并行:

并发(concurrency):指一个处理器同时处理多个任务。指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,即把时间分成若干段,使多个进程快速交替的执行。

并行(parallel):指多个处理器或者是多核的处理器同时处理多个不同的任务。在同一时刻,有多条指令在多个处理器上同时执行。

 

 参考:

http://blog.csdn.net/gengshenghong/article/details/7000979

http://blog.csdn.net/lanbing510/article/details/17108451

http://blog.sina.com.cn/s/blog_66474b160100z15b.html

http://www.cnblogs.com/xudong-bupt/p/3622101.html

https://www.cnblogs.com/hantan2008/p/5961312.html

 

你可能感兴趣的:(c++,调试笔记)