多核程序设计讲稿.ppt
多核程序设计多核程序设计第一页,讲稿共三十页哦OpenMP编程简介编程简介p一种面向共享内存以及分布式共享内存的多处理器多线程并行编程语言。p一种能够被用于显示指导多线程、共享内存并行的应用程序编程接口(API)。pOpenMP具有良好的可移植性,支持多种编程语言pOpenMP能够支持多种平台,包括大多数的类UNIX系统以及Windows NT系统(Windows 2000,Windows XP,Windows Vista等)。p用C/C+语言来实现OpenMP的多线程编程。http:/www.openmp.orgCurrent spec is OpenMP 2.5 250 Pages(combined C/C+and Fortran)第二页,讲稿共三十页哦2023/4/22OpenMP多线程编程基础多线程编程基础pOpenMP的编程模型以线程为基础,通过编译指导语句来显示地指导并行化,为编程人员提供了对并行化的完整的控制。pOpenMP程序的执行模型采用Fork-Join的形式nFork,创建新线程或者唤醒已有线程;Join,即多线程的汇合nFork-Join执行模式在开始执行时,只有一个叫主线程的运行线程存在。n主线程在运行中,需要进行并行计算时,派生出线程执行并行任务。n在并行执行时,主线程和派生线程共同工作。n在并行代码结束后,派生线程退出或挂起,控制流程回到单独的主线程中。第三页,讲稿共三十页哦2023/4/23OpenMP多线程编程基础多线程编程基础p共享内存多线程应用程序的Fork-Join模型如图n主线程运行中,遇到并行编译指导语句,根据环境变量派生出线程n某个派生线程遇到另一个编译指导语句,又派生出另外一组线程。n新线程组在通过一个隐含的同步屏障后,汇合成原有的线程。MasterThreadParalllRegionNestedParallelRegion第四页,讲稿共三十页哦2023/4/24OpenMP多线程编程基础多线程编程基础pOpenMP同时支持C/C+语言和Fortran语言,可选择任意一种语言及支持OpenMP的编译器编写OpenMP程序。pOpenMP应用程序的三个组成部分n编译指导语句n运行时库函数n环境变量:通过环境变量的方式可以灵活控制程序的运行。p例如:通过环境变量OMP_NUM_THREADS值控制运行的线程的数目第五页,讲稿共三十页哦2023/4/25OpenMP多线程编程基础多线程编程基础p编译指导语句n在编译器编译程序的时候,会识别特定的注释,而这些特定的注释就包含着OpenMP程序的一些语义。具体形式如下:#pragma omp clause,clause所有编译指导语句都以#pragma omp开始,后面跟具体的功能指令。其中directive部分就包含了具体的编译指导语句,包括parallel,for,parallel for,section,sections,single,master,critical,flush,ordered和atomic。可选子句clause给出了相应的编译指导语句的参数。第六页,讲稿共三十页哦2023/4/26OpenMP多线程编程基础多线程编程基础p运行时库函数n使用运行时函数库所包含的函数,必须在相应的源文件中包含OpenMP头文件,即#include“omp.h”n四个最常用的OpenMP库函数int omp_get_num_threads(void)返回当前使用的线程个数。int omp_set_num_threads(int NumThreads)在进入并行区域前,该函数设置将要使用的线程个数。int omp_get_thread_num(void)返回当前线程号,值在0(主线程)到线程总数减1之间。int omp_get_num_procs(void)返回可用的处理核(处理器)个数。支持超线程技术的处理核或处理器将被算作两个处理核(或两个处理器)。第七页,讲稿共三十页哦2023/4/27使用使用Visual Studio 2005编写编写OpenMP程序程序p当前的Visual Studio.Net 2005完全支持OpenMP 2.0标准,通过新的编译器选项/openmp来支持OpenMP程序的编译和链接。#include“omp.h”第八页,讲稿共三十页哦2023/4/28环境变量的设置环境变量的设置第九页,讲稿共三十页哦2023/4/29OpenMP程序编写步骤程序编写步骤p生成Console项目;p配置项目,使之支持OpenMP;p编写代码,加入#include“omp.h”;p编写源程序;p配置环境变量OMP_NUM_THREADS,确定线程数目;p执行程序。第十页,讲稿共三十页哦2023/4/210用用用用Visual Studio 2005Visual Studio 2005编写简单的编写简单的编写简单的编写简单的OpenMPOpenMP程序程序程序程序#include“stdafx.h”#include“omp.h”int _tmain(int argc,_TCHAR*argv)printf(“Hello from serial.n”);printf(“Thread number=%dn”,omp_get_thread_num();/串行执行#pragma omp parallel /开始并行执行printf(“Hello from parallel.Thread number=%dn”,omp_get_thread_num();printf(“Hello from serial again.n”);return 0;Example 1:Modify the“Hello World”serial code to run multithreaded using OpenMP 第十一页,讲稿共三十页哦2023/4/211用用用用Visual Studio 2005Visual Studio 2005编写简单的编写简单的编写简单的编写简单的OpenMPOpenMP程序程序程序程序pOpenMP程序使用到的环境变量OMP_NUM_THREADS设置为4p三次执行的结果第十二页,讲稿共三十页哦2023/4/212OpenMP编程技术编程技术循环并行化循环并行化p在C/C+语言中,循环并行化编译指导语句的格式#pragma omp parallel for clauseclausefor(index=first;test_expression;increment_expr)body of the loop;或或#pragma omp parallel#pragma omp for for(index=first;test_expression;increment_expr)body of the loop;n使用这个编译指导语句能将for循环中的工作分配到一个线程组中,线程组中的每一个线程将完成循环中的一部分内容。nfor循环语句要紧跟在parallel for的编译指导语句后面,编译指导语句的功能区域一直延伸到for循环语句的结束部分。n编译指导语句后面的子句(clause)用来控制编译指导语句的具体行为。第十三页,讲稿共三十页哦2023/4/213OpenMP编程技术编程技术循环并行化循环并行化p循环并行化语句的限制n循环并行化的语句必须具有如下的形式for(index=start;index end;increment_expr)其中小于号()也可以被其他的比较操作符替代,即可以替换成,=。n循环语句块应该是单入口与单出口的p不能使用break语句,也不能使用goto和return从循环中跳出,会使循环次数无法确定。但可以使用continue,其不影响循环执行的次数。第十四页,讲稿共三十页哦2023/4/214OpenMP编程技术编程技术循环并行化循环并行化p简单循环并行化(实验1)n例将两个向量相加,并将结果保存到第三个向量中,for(int i=0;in;i+)zi=xi+yi;n此向量加法没有数据相关性,循环过程的计算也没有循环依赖性(即某一次循环的结果依赖于其他次循环的结果)可以使用循环并行化编译指导语句直接对循环进行并行化。#pragma omp parallel for for(int i=0;in;i+)zi=xi+yi;n例 for(int i=0;in;i+)zi=zi-1+xi+yi;n此循环具有循环依赖性,进行并行化时必须考虑,不能简单进行。第十五页,讲稿共三十页哦2023/4/215循环并行化编译指导语句的子句循环并行化编译指导语句的子句p循环并行化编译指导语句的子句n数据作用域子句p作用域用来控制某一个变量是否是在各线程之间共享或者是某一个线程所私有。p数据作用域子句用shared表示一个变量在各线程之间共享,用private表示一个变量是某个线程私有的。p在OpenMP中,默认的变量作用域是共享的。n用来控制线程调度的子句(schedule子句)n动态控制是否并行化子句(if子句)n进行同步的子句(ordered子句)n控制变量在串行部分与并行部分传递的子句(copyin子句)第十六页,讲稿共三十页哦2023/4/216循环并行化循环并行化循环嵌套循环嵌套p循环嵌套(实验2)n循环并行化编译指导语句可以加在任意一个循环之前,则对应的最近的循环语句被并行化,其它部分保持不变。实际上并行化是作用于嵌套循环中的某一个循环。int i,j;#pragma omp parallel for private(j)for(i=0;i2;i+)for(j=6;j10;j+)printf(“i=%d j=%dn”,i,j);并行化作用于外层循环int i,j;for(i=0;i2;i+)#pragma omp parallel for private(j)for(j=6;j10;j+)printf(“i=%d j=%dn”,i,j);并行化作用于内层循环 在执行过程中,并行执行的效果只与有作用的循环相关,在每一个并行执行线程的内部,程序继续按照串行执行。第十七页,讲稿共三十页哦2023/4/217循环并行化循环并行化数据作用域子句数据作用域子句n确定数据共享属性的数据作用域子句有以下4个pshared用来显示定义的一个变量作用域是共享的。pprivate用来显示定义的一个变量作用域是私有的。pfirstprivate将串行的变量值复制到同名的私有变量中,且在每一个线程开始执行的时候初始化一次。lastprivate将并行执行中的最后一次循环的私有变量值复制到同名的串行变量中。pdefault语句用来改变变量的默认私有属性。只在Fortran里面有,在C/C+语言中没有default(shared)第十八页,讲稿共三十页哦2023/4/218循环并行化中循环并行化中firstprivate与与lastprivate子句子句p私有变量的初始化和终结操作nOpenMP编译指导语句使用firstprivate在循环并行化开始时用主线程中变量的值初始化各线程的同名私有变量。n使用lastprivate将循环并行化的最后一次循环的变量结果返回给主线程的同名变量。n实验3int val=8;#pragma omp parallel for firstprivate(val)lastprivate(val)for(int i=0;i2;i+)printf(i=%d val=%dn,i,val);if(i=1)val=10000;printf(i=%d val=%dn,i,val);printf(val=%dn,val);第十九页,讲稿共三十页哦2023/4/219并行区域编程并行区域编程p通过循环并行化编译指导语句使得一段代码能够在多个线程内部同时执行。循环并行化是并行区域编程的特例。p并行区域编译指导语句的格式与使用限制#pragma omp parallel clauseclauseblockpparallel编译指导语句的执行过程#pragma omp parallelfor(int i=0;i5;i+)printf(hello world i=%dn,i);程序的执行结果:hello world i=0hello world i=0hello world i=1hello world i=1hello world i=2#pragma omp parallel forfor(int i=0;i5;i+)printf(hello world i=%dn,i);程序的执行结果:hello world i=0hello world i=3hello world i=1hello world i=4hello world i=2hello world i=2hello world i=3hello world i=3hello world i=4hello world i=4第二十页,讲稿共三十页哦2023/4/220并行区域编程并行区域编程p并行区域与循环并行化的区别n并行区域采用复制执行的方式,将代码在所有的线程内部都执行一次n循环并行化则采用工作分配的执行方式,将循环所需的工作量按照一定的方式分配到各个执行线程中,所有线程执行工作的总和是原先串行执行所完成的工作量。p并行区域parallel语句的作用n当程序遇到parallel编译指导语句时,就会生成相应数目(根据环境变量)的线程,且组成一个线程组,并将代码重复地在各个线程内部执行。第二十一页,讲稿共三十页哦2023/4/221并行区域编程并行区域编程copyin,threadprivate子句子句使用使用copyin子句对线程私有的全局变量进行初始化。(实验子句对线程私有的全局变量进行初始化。(实验4)使用使用threadprivate子句用来标明某一全局变量是线程私有数据,在程子句用来标明某一全局变量是线程私有数据,在程序运行的过程中,不能被其他线程访问到。序运行的过程中,不能被其他线程访问到。int global=0;#pragma omp threadprivate(global)int _tmain(int argc,TCHAR*argv)global=1000;#pragma omp parallel copyin(global)printf(global=%dn,global);global=omp_get_thread_num();printf(global=%dn,global);printf(parallel againn);#pragma omp parallelprintf(global=%dn,global);通过copyin的操作,确实将线程的私有变量初始化为主线程中相应的全局变量的值。在并行区域执行完毕退出后,主线程与子线程中的相应的全局变量继续有效,并在再一次进入并行区域时,使用上一次退出时所赋的值。第二十二页,讲稿共三十页哦2023/4/222并行区域之间的工作共享并行区域之间的工作共享-使用循环语句分配任务使用循环语句分配任务n使用循环语句分配任务(实验5)#pragma omp parallelprintf(outside loop thread=%dn,omp_get_thread_num();#pragma omp forfor(int i=0;i4;i+)printf(inside loop i=%d thread=%dn,i,omp_get_thread_num();在循环的外部,程序代码被各个线程复制执行,而在循环的内部,循环的所有任务被各个线程分别完成。从总体上说,循环执行的次数与串行执行的次数一致。在OpenMP编程规范中已经对能够在不同的线程中执行不同的任务有所支持。使用工作分区使用工作分区(sections)的方法的方法第二十三页,讲稿共三十页哦2023/4/223并行区域之间的工作共享并行区域之间的工作共享-工作分区编码工作分区编码p工作分区编码(sections)n工作分区(任务分区)可以指导OpenMP编译器和运行时函数库将应用程序中标示出的分区块分配到用于执行并行区域的一组线程上。n分区块被划分到各个线程上,每个分区块仅执行一次每个分区块仅执行一次,并且各个分区块之间是并行执行的。n如果程序中包含的分区块个数比线程数多,那么剩下的分区块将在所有线程执行完前面的分区块后得到调度。n在使用工作分区的时候,各个线程自动从各个分区中获得任务执行,并且执行完一个分区的时候,如果分区组里还有未完成的工作,则继续取得任务完成。第二十四页,讲稿共三十页哦2023/4/224并行区域之间的工作共享并行区域之间的工作共享-工作分区编码工作分区编码p工作分区编码(sections)#pragma omp parallel sections#pragma omp sectionprintf(section 1 thread=%dn,omp_get_thread_num();#pragma omp sectionprintf(section 2 thread=%dn,omp_get_thread_num();#pragma omp sectionprintf(sectino 3 thread=%dn,omp_get_thread_num();程序运行结果为:section 1 thread=0section 2 thread=1sectino 3 thread=0 在使用工作分区编码的时候,各个线程自动从各个分区中获得任务执行,并且在执行完一个分区的时候,如果分区组里还有未完成的工作,则继续取得任务完成。第二十五页,讲稿共三十页哦2023/4/225OpenMP线程同步线程同步原子操作原子操作n原子操作p是OpenMP编程方式给同步编程带来的特殊的编程功能,通过编译指导语句的方式直接获取了现在多处理器计算机体系结构的功能。通过#pragma omp atomic编译指导语句提供。p使用原子语句的前提是相应的语句块能转化成一条机器指令,使得相应的功能能一次执行完毕而不会被打断。p在C/C+语言中可能的原子操作:”+*-/&|”#pragma omp atomicx=expr或者#pragma omp atomicx+/or x-,-x,+x第二十六页,讲稿共三十页哦2023/4/226OpenMP线程同步线程同步原子操作原子操作p当对一个数据进行原子操作保护的时候,就不能对数据进行临界区的保护,因为这是两种完全不同的保护机制,OpenMP运行时并不能在这两种保护机制之间建立配合机制,所以用户在针对同一个内存单元使用原子操作的时候需要在程序所有涉及到的部位都加入原子操作的支持。实验6int counter=0;#pragma omp parallel for(int i=0;i10000;i+)#pragma omp atomic /原子操作原子操作 counter+;printf(counter=%dn,counter);第二十七页,讲稿共三十页哦2023/4/227OpenMP的四种调度方案的四种调度方案p为了在多个处理器核之间调节工作负载,可使用schedule(type,chunksize)子句来提供循环调度信息,使编译器和运行时库能更好地划分迭代并将迭代分布到各个线程,从而实现更好的负载平衡。#pragma omp parallel for schedule(type,chunksize)其中type=static|dynamic|guided|runtime chunksize指每次调度的块大小pOpenMP的四种调度方案n静态调度staticn动态调度dynamicn指导性自调度guidednruntime在运行时根据环境变量确定调度类型第二十八页,讲稿共三十页哦2023/4/228pschedule(static)静态分配约n/t个连续迭代到每个线程;pschedule(static,C)将数据块静态地轮换分配给各个任务,每个数据块包括C个连续的迭代;(实验7)pschedule(dynamic)动态地将迭代逐个分配到各个线程;pschedule(dynamic,C)给各个任务动态分配任务块,每个任务块包括C个迭代;(实验8)pschedule(guided,C)开始时每个任务会分配到较大的迭代块,之后任务每次请求新的迭代时会被分配到大小递减的迭代块,迭代块大小将指数地下降到C;(实验9)pschedule(guided)进行指导性自调度,块最小为1;pschedule(runtime)在运行时根据环境变量OMP_SCHEDULE确定调度类型。OpenMP的四种调度方案的四种调度方案第二十九页,讲稿共三十页哦2023/4/229谢谢谢谢第三十页,讲稿共三十页哦