OpenMP: 使用OpenMP优化程序

OpenMP简介

        CPU的发展发展已经不再是司空见惯的提高时钟速度啦,功率和散热已经变成了CPU时钟速度提高的热点问题,而是转向了并行处理能力提高,如何充分利用多核处理器和超线程处理器开始成为软件设计中的焦点。OpenMP™ 应用程序接口是与多家计算机供应商联合开发的、针对共享内存多处理器体系结构的可移植并行编程模型。其规范由“OpenMP 体系结构审核委员会”创立并公布。OpenMP是一个很快速、有效的高性能计算的解决方案,同时OpenMP是一个可移植的、工业标准化的API,也是一个C/c++语言的编程协议,可以支持并行程序开发。OpenMP最新版本是2.5,并且已经出台了3.0标准草案,Visual C++® 2005提供了对2.0标准的完整支持,OpenMP同时也支持Xbox 360™平台。

Visual C++® 2005对OpenMP的支持

       VC++2005根据项目属性的配置指示进行new /openmp编译器切换,当配置了OpenMP支持后,编译器会提供_OPENMP定义,可以使用#ifdef _OPENMP来决定程序使用或者不使用OpenMP。

       配置VC++2005项目,在project的property页面上的C/C++ -> Language 选项卡中将OpenMP Support这项设置为Yes,在需要使用OpenMP函数的cpp文件中引用#include ,这样设置就完成了。

VS++不支持OpenMP运行时库静态链接。

HelloWorld!!!

        还是从HelloWorld还看一下OpenMP的简单使用,新建一个HelloWorld vc++ 2005解决方案Win32控制台程序,设置项目属性为支持OpenMP(参考上面设置方法),编写HelloWorld程序如下:

#include 
#include 
int _tmain(int argc, _TCHAR* argv[])
{
    #pragma omp parallel
    { 
        printf("Hello World/n");
    }
    getchar();
    return 0;
}

程序输出结果

Hello World

Hello World

线程组

        打开了OpenMP功能开关的编译器会自动生成相应的代码,将并行执行的程序语句分割成多个并行的程序段,每个程序段都可以独立地执行。具体分割成几个程序段取决于所运行的硬件平台,OpenMP的运行时间,已经程序员已经设置好的选项设置等。

        当程序进入一个并行代码段时,线程组就开始工作了。当线程完成他们各自的工作后,线程又开始休息,等待下一个并行代码段(有点像线程池的概念)。允许嵌套并行程序区段。

嵌套并行执行模型

        OpenMP 采用 fork-join (分叉- 合并)并行执行模式。线程遇到并行构造时,就会创建由其自身及其他一些额外(可能为零个)线程组成的线程组。遇到并行构造的线程成为新组中的主线程。组中的其他线程称为组的从属线程。所有组成员都执行并行构造内的代码。如果某个线程完成了其在并行构造内的工作,它就会在并行构造末尾的隐式屏障处等待。当所有组成员都到达该屏障时,这些线程就可以离开该屏障了。主线程继续执行并行构造之后的用户代码,而从属线程则等待被召集加入到其他组。

        OpenMP 并行区域之间可以互相嵌套。如果禁用嵌套并行操作,则由遇到并行区域内并行构造的线程所创建的新组仅包含遇到并行构造的线程。如果启用嵌套并行操作,则新组可以包含多个线程。

        OpenMP 运行时库维护一个线程池,该线程池可用作并行区域中的从属线程。当线程遇到并行构造并需要创建包含多个线程的线程组时,该线程将检查该池,从池中获取空闲线程,将其作为组的从属线程。如果池中没有足够的空闲线程,则主线程获取的从属线程可
能会比所需的要少。组完成执行并行区域时,从属线程就会返回到池中。

使用规范

语法结构

#pragma omp [clause[ [,] clause]...]

directive包括: parallel, for, parallel for, section, sections, single, master, critical, flush, ordered, atomic

clauses:可修改对directive行为的影响,master, critical, flush, ordered, atomic不接受任何的clauses

支持并行

#pragma omp parallel [clause[ [, ]clause] ...]

structured-block

parallel指示是最常用到的啦,前面看到的HelloWorld程序就包含了该指示的使用,下面再看一个更加复杂一点的程序

// 使用矩阵拟合法计算圆周率
void  CalcPI() 
{ 
    time_t   start,   finish ,current; 
    static   long   num_steps   =   10000; 
    double   step; 
    int   i;                     
    double   x,   pi,   sum   =   0.0; 
    step   =   1.0/(double)   num_steps; 
    start   =   clock(); 
#pragma   omp   parallel   for   reduction(+:sum)   private(x)             /*只加了这一句,其他不变*/ 
    for   (i=0;i <   num_steps;   i++) 
    { 
        x   =   (i+0.5)*step; 
        sum   =   sum   +   4.0/(1.0+x*x);
        current = clock();
        printf( "I   =   %d   %ld ms/n ",  i,current-start   ); 
    } 
    pi   =   step   *   sum; 
    finish   =   clock(); 
    printf( "Pi   =   %16.15f   (%d   steps),   %ld   ms/n ",   pi,   num_steps,   finish-start   ); 
    return; 
}

        可是使用不同的多核机器和改变num_steps 的值来对该程序进行测试,可以知道该程序执行的过程和计算所花费的时间。

小结

        对OpenMP的一些基本原理进行了介绍,并且介绍了vc++2005对OpenMP的支持,通过两个经典的例子对OpenMP进行了简单的编程实践,更多详细的技术细节需要去其官方网站参考《OpenMP C and C++ Application Program Interface》

参考资料

MSDN :http://msdn.microsoft.com/msdnmag/issues/05/10/OpenMP/

OpenMP:http://www.openmp.org

Other:http://topic.csdn.net/u/20070618/11/f3fdb440-e3d4-410a-ae97-783e1cec1d59.html

你可能感兴趣的:(OpenMP)