OpenMP 并行编程

最近开始学习并行编程,目的是为了提高图像处理的运行速度,用的是VS2012自带的OpenMP。

如何让自己的编译器支持OpenMP: 1) 点击 项目属性页 2)点击 配置 3)点击 [C/C++] 4)点击 语言 5)选中OpenMP支持

OpenMP 的构成:编译器指令 + 运行时例程;

编译器指令: 以 #pragma omp 开头,用以告知编译器哪一段代码需要并行。

运行时例程:必须包括omp.h 设置和获取执行环境相关的信息,也包括一系列用以同步的API;

编译器指令格式如下: #pragma omp <directive> [clause[ [,] clause]…]   #pragma omp <指令> [子句,子句....]

dierctive(指令)包含如下几种:parallel,for,parallel for,section,sections,single,master,criticle,flush,ordered和atomic。这些指令指定要么是用以工作共享要么是用以同步。

对指令而言,子句是可选的,子句可以影响到指令的行为。五个指令(master,cirticle,flush,ordered和atomic)不能使用子句!!

最常用,最重要的指令: parallel

parallel:这条指令为动态长度的结构化程序块创建一个并行区域。

这条指令告知编译器这一程序块应被多线程并行执行。每一条指令都执行一样的指令流,但可能不是完全相同的指令集合。这可能依赖于if-else这样的控制流语句

int i = 0;
    #pragma omp parallel

{
    i++;
printf(" %d   ",i);

}
    Sleep(10000);

这一段代码的输出可以判断自己的电脑是几个核的;

#pragma omp for:工作共享指令  告诉OpenMP将紧随的for循环的迭代工作分给线程组并行处理;

#pragma omp parallel

{
#pragma omp for
for(int i = 1; i < size; ++i)

        x[i] = (y[i-1] + y[i+1])/2;

}

//下面一段代码是上面一段代码的简写

#pragma omp parallel for

for(int i = 1; i < size; ++i)

x[i] = (y[i-1] + y[i+1])/2;

这一程序在并行区域的结束处需要同步,即所有的线程将阻塞在并行区域结束处,直到所有线程都完成。

注意:::

如果前面的代码没有使用#pragma omp for指令,那么每一个线程都将完全执行这个循环,造成的后果就是线程冗余计算;

要使用并行循环,必须你必须确保没有循环依赖,即循环中的某一次迭代不依赖于其它迭代的结果。

另外,OpenMP对在#pragma omp for或#pragma omp parallel for里的循环体有形式上的限制,循环必须使用下面的形式:

for([integer type] i = loop invariant value;

    i {<,>,=,<=,>=} loop invariant value;

    i {+,-}= loop invariant value)

这样OpenMP才能知道在进入循环时需要执行多少次迭代。

共享数据与私有数据:

  OpenMP让共享和私有的差别显而易见,并且你能手动干涉。

共享变量在线程组内的所有线程间共享。因此在并行区域里某一条线程改变的共享变量可能被其它线程访问。反过来说,在线程组的线程都拥有一份私有变量的拷贝,所以在某一线程中改变私有变量对于其它线程是不可访问的。

默认地,并行区域的所有变量都是共享的。

除非如下三种特别情况:

一、在并行for循环中,循环变量是私有的。

如下里面的例子,变量i是私有的,变量j默认是共享的,但使用了firstprivate子句将其声明为私有的。

#pragma omp parallel

{

   #pragma omp for firstprivate(j) lastprivate(i) reduction(+: sum)//变量i,j和sum是线程组里每一个线程的私有变量,它们将被拷贝到每一个线程。

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

   {

      int doubleI = 2 * i;

      for(; j < doubleI; ++j)

      {

         sum += myMatrix.GetElement(i, j);

      }

   }

}

二、并行区域代码块里的本地变量是私有的。

三、所有通过private,firstprivate,lastprivate和reduction子句声明的变量为私有变量。

这四个子句每个都有一序列的变量,但它们的语义完全不同。private子句说明变量序列里的每一个变量都应该为每一条线程作私有拷贝。这些私有拷贝将被初始化为默认值(使用适当的构造函数),例如int型的变量的默认值是0。

firstprivate有着与private一样的语义外,它使用拷贝构造函数在线程进入并行区域之前拷贝私有变量。

lastprivate有着与private一样的语义外,在工作共享结构里的最后一次迭代或者代码段执行之后,lastprivate子句的变量序列里的值将赋值给主线程的同名变量,如果合适,在这里使用拷贝赋值操作符来拷贝对象。

reduction与private的语义相近,但它同时接受变量和操作符(可接受的操作符被限制为图4列出的这几种之一),并且reduction变量必须为标量变量(如浮点型、整型、长整型,但不可为std::vector,int[]等)。reduction变量初始化为图4表中所示的值。在代码块的结束处,为变量的私有拷贝和变量原值一起应用reduction操作符。

循环嵌套:

omp_set_nested()用于设置是否允许OpenMP进行嵌套并行,默认的设置为false。

什么是嵌套并行?就是在并行区域中嵌套另一个并行区域,如下:

    #pragma omp parallel num_threads(5)
        {
    #pragma omp parallel num_threads(5) {/*do sth */}
        }  

该如何执行?是执行5次?还是5×5次?这就是由是否嵌套并行来决定的,默认设置为不允许(false),所以会执行5次。

int main()
    {
        omp_set_nested(10);     // none zero value is OK!  

    #pragma omp parallel num_threads(2)
        {
            printf("ID: %d, Max threads: %d, Num threads: %d \n",omp_get_thread_num(), omp_get_max_threads(), omp_get_num_threads());
    #pragma omp parallel num_threads(5)
            printf("Nested, ID: %d, Max threads: %d, Num threads: %d \n",omp_get_thread_num(), omp_get_max_threads(), omp_get_num_threads());
        }  

        return 0;
    }  

由调试结果可以看出来,运行过程中,先生成两个线程,再由这个两个线程各分出五个线程。

omp_get_thread_num,获取的ID是在当前嵌套层所在的线程组的ID。

omp_get_num_threads,获取的也是当前所在层的线程组的线程数量。

omp_get_max_threads,与线程的数量和执行等都无关,这是一个可以分析出来的值。

非循环并行

OpenMP经常用以循环层并行,但它同样支持函数层并行,这个机制称为OpenMP sections。sections的结构是简明易懂的,并且很多例子都证明它相当有用。

#pragma omp parallel sections
  {
     #pragma omp section
        //......一个并行区域
     #pragma omp section
       //......另一个并行区域
  }

参考链接:http://blog.csdn.net/augusdi/article/details/8807699

http://blog.csdn.net/gzlaiyonghao/article/details/1503817

http://blog.csdn.net/augusdi/article/details/8807119

时间: 2024-10-21 21:50:19

OpenMP 并行编程的相关文章

OpenMP并行编程应用—加速OpenCV图像拼接算法

OpenMP是一种应用于多处理器程序设计的并行编程处理方案,它提供了对于并行编程的高层抽象.仅仅须要在程序中加入简单的指令,就能够编写高效的并行程序,而不用关心详细的并行实现细节.减少了并行编程的难度和复杂度.也正由于OpenMP的简单易用性,它并不适合于须要复杂的线程间同步和相互排斥的场合. OpenCV中使用Sift或者Surf特征进行图像拼接的算法.须要分别对两幅或多幅图像进行特征提取和特征描写叙述,之后再进行图像特征点的配对.图像变换等操作.不同图像的特征提取和描写叙述的工作是整个过程中

并行编程笔记Outline

Motivation 前几周的面试失败了,应该是留下了空谈的印象.看到简历上职业规划中“着手准备操作系统级.语言级计算基础设施”,深感自己大言不惭. 吹过的牛就是含着泪也得做完. Audience myself Scope 操作系统级进程.线程:APUE 共享内存式并行:Java(Python?).POSIX threads.OPenMP 分布式内存并行:MPI.Erlang(填充完Erlang OTP) CUDA(?) References [1] Pacheco P. S.. 并行程序设计导

OpenMP并行程序设计——for循环并行化详解

转载请声明出处http://blog.csdn.net/zhongkejingwang/article/details/40018735 在C/C++中使用OpenMP优化代码方便又简单,代码中需要并行处理的往往是一些比较耗时的for循环,所以重点介绍一下OpenMP中for循环的应用.个人感觉只要掌握了文中讲的这些就足够了,如果想要学习OpenMP可以到网上查查资料. 工欲善其事,必先利其器.如果还没有搭建好omp开发环境的可以看一下OpenMP并行程序设计--Eclipse开发环境的搭建 首

多核并行编程方法

在多核的硬件结构中,如果要充分发挥硬件的性能,必须采用多线程(或多进程)执行,以提高CPU的利用率.多核系统的编程模型和多个CPU的SMP系统的编程模型是一致的,都属于共享存储的编程模型:同时,多核环境中也可以使用的分布式编程模型.目前,多核并行编程方法可以分为以下四类:基于Raw Thread API的方法.基于共享内存编程模型的方法.基于高层次模板库的方法.基于分布式编程的方法.(1)基于Raw Thread API的方法:这种方法主要使用系统底层API来进行多线程编程.Windows Th

并行计算复习————第四篇 并行计算软件支撑:并行编程

并行计算复习 第四篇 并行计算软件支撑:并行编程 Ch13 并行程序设计基础 13.1并行语言构造方法 库例程:MPI.Pthreads 扩展串行语言:Fortran90 加编译注释构造:OpenMP 13.2并行性问题 可利用SPMD来伪造MPMD 需要运行MPMD:parbegin S1 S2 S3 parend 可以改造成SPMD: for i = 1 to 3 par-do if i == 1 then S1 else if i == 2 then S2 else if i == 3 t

五种主要多核并行编程方法分析与比较

随着多核时代的到来与流行,传统的单线程串行程序的编程模式必将改变,取而代之的将是并行编程.目前已经有五种主要并行编程模型,下面将对此五种模型进行概括性的分析与比较: 1. MPI MPI(Message Passing Interface)消息传递接口是MPI论坛发布的一个库,而不是一门实现语言,支持C/C++/Fortran.是一种消息传递编程模型,为进程间通信服务.MPI提供了一种与平台无关,可以被广泛使用的编写消息传递程序的标准.用它来编写消息传递程序,不仅实用.可移植.高效和灵活,而且和

并行编程入门

目录 1. 并行编程简介 2. MapReduce 2.1 MapReduce简介 2.2 MapReduce框架 2.3 Hadoop介绍 2.4 Hadoop基本类 2.5 Hadoop编程实例 1.并行编程简介 1.1.并行编程作用,用途 商业用途,科学计算,大数据分析 1.2.并行编程兴起原因 目前的串行编程的局限性 使用的流水线等隐式并行模式的局限性 硬件的发展 1.3.并行算法设计原则步骤 a.分析问题 b.分解问题 其中分解方法有: 数据分解 递归分解 探测性分解 推测性分解 混合

C#并行编程 z

目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 C#并行编程-线程同步原语 C#并行编程-PLINQ:声明式数据并行 背景 基于任务的程序设计.命令式数据并行和任务并行都要求能够支持并发更新的数组.列表和集合. 在.NET Framework 4 以前,为了让共享的数组.列表和集合能够被多个线程更新,需要添加复杂的代码来同步这些更新操作. 如您需要编写一个并行循环,这个循环以无序的方式向一个共享集合中添加元素,那么必须加入一个同步机制

.Net中的并行编程-4.实现高性能异步队列

上文<.Net中的并行编程-3.ConcurrentQueue实现与分析>分析了ConcurrentQueue的实现,本章就基于ConcurrentQueue实现一个高性能的异步队列,该队列主要用于实时数据流的处理并简化多线程编程模型.设计该队列时考虑以下几点需求(需求来自公司的一个实际项目): 1. 支持多线程入队出队,尽量简化多线程编程的复杂度. 2. 支持事件触发机制,数据入队时才进行处理而不是使用定时处理机制, 而且内部能阻塞消费者线程. 3. 出队时数据处理的顺序要保证和入队时是一致