您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 企业文化 > 第3天上午 OpenMP编程
一种面向共享内存以及分布式共享内存的多处理器多线程并行编程语言。一种能够被用于显示指导多线程、共享内存并行的应用程序编程接口(API)。OpenMP具有良好的可移植性,支持多种编程语言OpenMP能够支持多种平台,包括大多数的类UNIX系统以及WindowsNT系统(Windows2000,WindowsXP,WindowsVista等)。OpenMP的编程模型以线程为基础,通过编译指导语句来显示地指导并行化,为编程人员提供了对并行化的完整的控制。采用Fork-Join的形式MasterThreadParalllRegionNestedParallelRegion编译指导语句◦在编译器编译程序的时候,会识别特定的注释,而这些特定的注释就包含着OpenMP程序的一些语义。#pragmaompdirective[clause[[,]clause]…]其中directive部分就包含了具体的编译指导语句,包括parallel,for,parallelfor,section,sections,single,master,critical,flush,ordered和atomic。◦将串行的程序逐步地改造成一个并行程序,达到增量更新程序的目的,减少程序编写人员一定的负担。运行时库函数◦OpenMP运行时函数库原本用以设置和获取执行环境相关的信息,它们当中也包含一系列用以同步的API。◦支持运行时对并行环境的改变和优化,给编程人员足够的灵活性来控制运行时的程序运行状况。环境变量#include“omp.h”编译指导语句环境变量1)生成Console项目;2)配置项目,使之支持OpenMP;3)编写代码,加入#include“omp.h”;4)编写源程序;5)配置环境变量OMP_NUM_THREADS,确定线程数目;6)执行程序。循环并行化编译指导语句的格式#pragmaompparallelfor[clause[clause…]]for(index=first;test_expression;increment_expr){bodyoftheloop;}循环并行化语句的限制◦循环并行化的语句必须具有如下的形式for(index=start;indexend;increment_expr)◦循环语句块应该是单出口与单入口的循环嵌套◦循环并行化编译指导语句可以加在任意一个循环之前,则对应的最近的循环语句被并行化,其它部分保持不变。分析循环并行化例子OpenMP2在Windows下的程序计数器◦QueryPerformanceCounter◦QueryPerformanceFrequency循环嵌套的并行化◦OpenMP3Shared,private,firstprivate,lastprivate局部变量是私有的,堆数据区域是共享的intgval=8;voidfuncb(int*x,int*y,intz){staticintsv;intu;u=(*y)*gval;*x=u+z;}voidfunca(int*a,intn){inti;intcc=9;#pragmaompparallelforfor(i=0;in;i++){inttemp=cc;funcb(&a[i],&temp,i);}}运算符数据类型默认初始值+整数,浮点0*整数,浮点1-整数,浮点0&整数所有位都开启,~0|整数0^整数0&&整数1||整数0OpenMP4通过循环并行化编译指导语句使得一段代码能够在多个线程内部同时执行。并行区域编译指导语句的格式与使用限制#pragmaompparallel[clause[clause]…]blockparallel编译指导语句的执行过程#pragmaompparallelfor(inti=0;i5;i++)printf(helloworldi=%d\n,i);程序的执行结果:helloworldi=0helloworldi=1helloworldi=2helloworldi=3helloworldi=4#pragmaompparallelforfor(inti=0;i5;i++)printf(helloworldi=%d\n,i);程序的执行结果:helloworldi=0helloworldi=3helloworldi=1helloworldi=4helloworldi=2线程私有数据与threadprivate,copyin子句◦使用threadprivate子句用来标明某一个变量是线程私有数据,在程序运行的过程中,不能够被其他线程访问到。◦使用copyin子句对线程私有的全局变量进行初始化。intcounter=0;//usingthreadprivate#pragmaompthreadprivate(counter)voidinc_counter(){counter++;}int_tmain(intargc,TCHAR*argv[]){#pragmaompparallelfor(inti=0;i10000;i++)inc_counter();printf(counter=%d\n,counter);}intglobal=0;#pragmaompthreadprivate(global)int_tmain(intargc,TCHAR*argv[]){global=1000;#pragmaompparallelcopyin(global){printf(global=%d\n,global);global=omp_get_thread_num();}printf(global=%d\n,global);printf(parallelagain\n);#pragmaompparallelprintf(global=%d\n,global);}并行区域之间的工作共享工作队列◦工作队列的基本工作过程即为维持一个工作的队列,线程在并行执行的时候,不断从这个队列中取出相应的工作完成,直到队列为空为止。根据线程号分配任务◦由于每一个线程在执行的过程中的线程标识号是不同的,可以根据这个线程标识号来分配不同的任务。使用循环语句分配任务#pragmaompparallel{printf(outsideloopthread=%d\n,omp_get_thread_num());#pragmaompforfor(inti=0;i4;i++)printf(insideloopi=%dthread=%d\n,i,omp_get_thread_num();}工作分区编码(sections)#pragmaompparallelsections{#pragmaompsectionprintf(section1thread=%d\n,omp_get_thread_num());#pragmaompsectionprintf(section2thread=%d\n,omp_get_thread_num());#pragmaompsectionprintf(sectino3thread=%d\n,omp_get_thread_num());}程序运行结果为:section1thread=0section2thread=1sectino3thread=0OpenMP支持两种不同类型的线程同步机制◦互斥锁◦事件通知机制数据竞争inti;intmax_num=-1;#pragmaompparallelforfor(i=0;in;i++)if(ar[i]max_num)max_num=ar[i];互斥锁机制◦在OpenMP中,提供了三种不同的互斥锁机制用来对一块内存进行保护,它们分别是临界区(critical),原子操作(atomic)以及由库函数来提供同步操作。在程序需要访问可能产生竞争的内存数据的时候,都需要插入相应的临界区代码。临界区编译指导语句的格式如下所示:#pragmaompcritical[(name)]blockinti;intmax_num_x=max_num_y=-1;#pragmaompparallelforfor(i=0;in;i++){#pragmaompcritical(max_arx)if(arx[i]max_num_x)max_num_x=arx[i];#pragmaompcritical(max_ary)if(ary[i]max_num_y)max_num_y=ary[i];}原子操作是OpenMP编程方式给同步编程带来的特殊的编程功能,通过编译指导语句的方式直接获取了现在多处理器计算机体系结构的功能。通过#pragmaompatomic编译指导语句提供。只能作用在语言内建的基本数据结构。#pragmaompatomicxbinop=expr或者#pragmaompatomicx++//orx--,--x,++xintcounter=0;#pragmaompparallel{for(inti=0;i10000;i++)#pragmaompatomic//atomicoperationcounter++;}printf(counter=%d\n,counter);OpenMP通过一系列的库函数支持更加细致的互斥锁操作编译指导语句进行的互斥锁支持只能放置在一段代码之前,作用在这段代码之上。程序员必须自己保证在调用相应锁操作之后释放相应的锁,否则就会造成多线程程序的死锁。函数名称描述voidomp_init_lock(omp_lock_t*)初始化一个互斥锁voidomp_destroy_lock(omp_lock_t*)结束一个互斥锁的使用并释放内存voidomp_set_lock(omp_lock_t*)获得一个互斥锁voidomp_unset_lock(omp_lock_t*)释放一个互斥锁intomp_test_lock(omp_lock_t*)试图获得一个互斥锁,并在成功是返回真(true),失败是返回假(false)影响性能的主要因素◦根据Amdahl定律,我们应当努力提高并行化代码在应用程序中的比率,这是通用的提高效率的方法。◦OpenMP本身的开销◦负载均衡如果各个线程之间的负载不均衡,就有可能造成某些线程在执行过程中无事可干,经常处于空闲状态;而另外一些线程则负担沉重,需要很长时间才能够完成任务。◦局部性◦线程同步带来的开销
本文标题:第3天上午 OpenMP编程
链接地址:https://www.777doc.com/doc-3393627 .html