关于OpenMP的一些资料

OpenMP的基本介绍

经过使用,觉得利用其来编写多线程应用程序确实蛮简单的,但是我只用到了,比较简单的部分。但是我觉得最应该注意的是你的代码需不需要进行并行化,并要测试并行化后代码的执行效率是否变高了!并且也要考虑CPU的核心数。

1.简介:OpenMPOpenMulti-Processing)是一套支持跨平台共享内存方式的多线程并发的编程API,使用C,C++Fortran语言,可以在大多数的处理器体系和操作系统中运行,包括Solaris,AIX, HP-UX, GNU/Linux, Mac OS X, MicrosoftWindows。包括一套编译器指令、库和一些能够影响运行行为的环境变量。

OpenMP采用可移植的、可扩展的模型,为程序员提供了一个简单而灵活的开发平台,从标准桌面电脑到超级计算机的并行应用程序接口。

OpenMP是一个跨平台的多线程实现,主线程(顺序的执行指令)生成一系列的子线程,并将任务划分给这些子线程进行执行。这些子线程并行的运行,由运行时环境将线程分配给不同的处理器。

2.历史:OpenMPArchitecture Review Board (ARB)199710月发布了OpenMP for Fortran 1.0。次年的10月,发布了C/C++的标准。2000年,发布了Fortran语言的2.0版本,并于2002年发布了C/C++语言的2.0版本。2005年,包含FortranC/C++2.5版本发布了。

20085月发布了3.0版。3.0中的新功能包括任务(tasks)和任务结构(task construct)的概念。这些新功能总结在OpenMP3.0规范的附录F中。 OpenMP规范的3.1版于201179日发布。

4.0版本在20137月发布,它增加或改进以下功能:支持加速器,原子性,错误处理,线程关联,任务扩展,减少用户定义的SIMD支持和Fortran 2003的支持。

 

3.优点:进入多核时代后,必须使用多线程编写程序才能让各个CPU核得到利用。在单核时代,通常使用操作系统提供的API来创建线程,然而,在多核系统中,情况发生了很大的变化,如果仍然使用操作系API来创建线程会遇到一些问题。具体来说,有以下三个问题:

1)CPU核数扩展性问题

多核编程需要考虑程序性能随CPU核数的扩展性,即硬件升级到更多核后,能够不修改程序就让程序性能增长,这要求程序中创建的线程数量需要随CPU核数变化,不能创建固定数量的线程,否则在CPU核数超过线程数量上的机器上运行,将无法完全利用机器性能。虽然通过一定方法可以使用操作系统API创建可变化数量的线程,但是比较麻烦,不如OpenMP方便。

2)方便性问题

在多核编程时,要求计算均摊到各个CPU核上去,所有的程序都需要并行化执行,对计算的负载均衡有很高要求。这就要求在同一个函数内或同一个循环中,可能也需要将计算分摊到各个CPU核上,需要创建多个线程。操作系统API创建线程时,需要线程入口函数,很难满足这个需求,除非将一个函数内的代码手工拆成多个线程入口函数,这将大大增加程序员的工作量。使用OpenMP创建线程则不需要入口函数,非常方便,可以将同一函数内的代码分解成多个线程执行,也可以将一个for循环分解成多个线程执行。

3)可移植性问题

目前各个主流操作系统的线程API互不兼容,缺乏事实上的统一规范,要满足可移植性得自己写一些代码,将各种不同操作系统的api封装成一套统一的接口。OpenMP是标准规范,所有支持它的编译器都是执行同一套标准,不存在可移植性问题。

4.编程模型

OpenMP的编程模型以线程为基础,通过编译指导语句来显示的指导并行化。其执行模型采用Fork-Join的形式。其三个组成部分为:1.编译指导语句;2.运行时库函数;3.环境变量。

1.     编译指导语句:#pragma omp <directive(具体的编译指导语句)> [clause[ [,]]…](编译指导语句的参数)

2.     四个最常用的OpenMP库函数:

intomp_get_num_threads(void):放回当前使用的线程数;

int omp_set_num_threads(int NumThreads);(此函数可以覆盖环境变量OMP_NUM_THREADS的值)

int omp_get_thread_num(void);返回当前线程号

int omp_get_num_procs(void);返回可用的处理器个数;

3.     循环并行化编译指导语句的子句

  1.数据作用域子句:其用来控制变量是否在个线程之间共享或是某一个线程所私有;其中shared为共享,private表示某个线程私有。默认为shared;

  2.控制线程调度的语句:schedule子句

  3.动态控制是否并行话子句:if语句

  4.进行同步的子句:ordered子句

  5.控制变量在串行部分与并行部分传递的子句:copyin子句

循环并行化采用工作分配的执行方式,将循环所需的工作量按照一定的方式分配到各个执行线程中,所有线程执行工作的总和是原先串行所完成的工作量;

4.     并行区域parallel语句的作用:当程序遇到此编译语句时,就会生成响应数目的线程,且组成一个线程组,并将代码重复地在各个线程内部执行。parallel末尾有一个隐含的屏障,所有线程完成所需的重复任务后,将这个同步屏障汇合。此线程组的主线程继续执行,而相应的子线程则停止执行;

工作分区编码(sections(在使用工作分区编码的时候,各个线程自动从各个分区中获得任务执行,并且在执行完一个分区的时候,如果分区里还有未完成的工作,则继续取得任务完成。)

#pragma omp parallel sections

{

#pragra omp section

…….

#pragra omp section

……..

}

5.     OpenMP支持两种不同类型的同步机制:

互斥锁机制:用来保护一块共享的存储空间,使得每一次访问此共享存储区的线程最多只有一个,从而保证了数据的完整性。

事件通知机制:保证了多个线程之间的执行顺序。控制规定线程执行顺序所需要的同步屏障,弟定序区段,主线程的执行等。

 

 

5多线程应用程序的性能分析:

影响性能的因素:

1.     OpenMP本身的开销:

1.并不是所有的并行化都可以带来好的高效率;

2.使用OpenMP进行并行化之后OpenMP本身引入的开销。因为OpenMP获得应用程序多线程并行化的能力需要程序库的支持,库中代码的运行会带来一定的开销;

3.只有并行化代码段负担足够大,而引入OpenMP本身的开销足够小,此时引入并行化操作才能加速程序的执行。

2.     负载均衡:

如果线程之间的负载不均衡,就有可能造成某些线程在执行过程中无事可干,经常处于空闲状态;而另一些线程则负担沉重,需要很长时间才能够完成任务。

 

3.     线程同步带来的开销:

1.     多个线程必然带来一定的同步开销,有的同步开销是不可避免的,有的同步则是不必要的;

2.     考虑同步的必要性,消除不必要的同步或调整同步的顺序,就有可能带来性能上的提升。

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值