1、2006年4月,共享存储编程,1/108,机群应用开发并行编程原理及程序设计Parallel Programming: Fundamentals and Implementation戴 荣曙光信息产业有限公司2006.4,2006年4月,共享存储编程,2/108,参考文献,黄铠,徐志伟著,陆鑫达等译. 可扩展并行计算技术,结构与编程. 北京:机械工业出版社, P.3356,P.227237, 2000.陈国良著.并行计算结构、算法、编程. 北京:高等教育出版社,1999.Barry Wilkinson and Michael Allen. Parallel Programming(Techni
2、ques and Applications using Networked Workstations and Parallel Computers). Prentice Hall, 1999.李晓梅,莫则尧等著. 可扩展并行算法的设计与分析. 北京:国防工业出版社,2000.张宝琳,谷同祥等著. 数值并行计算原理与方法. 北京:国防工业出版社,1999.都志辉著. 高性能计算并行编程技术MPI并行程序设计. 北京:清华大学出版社, 2001.,2006年4月,共享存储编程,3/108,相关网址,MPI: http:/ww.mpi-forum.org, http:/www.mcs.anl.gov
3、/mpiPthreads: http:/PVM: http:/www.epm.ornl.gov/pvm/ OpemMP: http:/www.openmp.org网上搜索:,2006年4月,共享存储编程,4/108,共享存储编程Programming with Shared Memory,2006年4月,共享存储编程,5/108,共享存储并行机模型,体系结构特点:多台处理机通过互联网络共享一个统一的内存空间,通过单一内存地址来实现处理机间的协调.内存空间也可由多个存储器模块构成.每台处理机可以执行相同或不同的指令流,每台处理机可以直接访问到所有数据.处理机间通信是借助于共享主存来实现的.可扩展
4、性差,当处理机需要同时访问共享全局变量时,产生内存竞争现象而严重影响效率,比较适合中小规模应用问题的计算和事务处理.,2006年4月,共享存储编程,6/108,共享存储编程标准与特点,共享存储器编程标准Pthreads(线程标准) X3H5(线程标准)OpenMP(最常用的共享存储并行编程方式,是我们讨论的重点.)共享存储器编程特点显式多线程库调用.(Pthreads).编译制导语句,OpenMP等.语言C,Fortran77,Fortran90/95,C+,2006年4月,共享存储编程,7/108,并行编程标准,线程库标准(Thread Library) Win32 API. POSIX t
5、hreads线程模型. X3H5:概念性线程模型编译制导(Compiler Directives) OpenMP - portable shared memory parallelism.,2006年4月,共享存储编程,8/108,为什么流行多线程编程?,线程:在进程的内部执行的指令序列.相对于进程,线程开销小:创建一个线程的时间大约是建立一个新进程的1/30。如在Sun4/75工作上站上,创建一个非绑定线程约为52微秒,而fork()一次的时间为1700微秒。线程同步时间约是进程同步时间的1/3.线程与RPC相结合,发挥多处理机的处理能力;发挥多处理器的处理能力;开发程序的并发性,改善程序的
6、结构.容易实现数据共享:由于线程共用内存地址,因此可实现数据共享例:一高性能Web服务器可为每一打开链接的浏览器分配一个线程,所有线程即可共用同一cache来访问网站的热点话题统一的标准:以前各开发商提供互不兼容的线程库,结果导致多线程程序不能很好地移值。自1995年的POSIX线程标准实施之后,极大地促进多线程编程的统一。各系统都支持Pthreads,如Linux、SUN、IBM AIX等。,2006年4月,共享存储编程,9/108,Pthreads线程模型,POSIX1003.4a小组研究多线程编程标准. 当标准完成后,大多数支持多线程的系统都支持POSIX接口.很好的改善了多线程编程的可
7、移植性.IEEE Portable Operating System Interface, POSIX, 1003.1-1995标准:POSIX线程模型:pthreads.,2006年4月,共享存储编程,10/108,线程管理(Pthread为例),创建:pthread_create终止:pthread_exit汇合:pthread_join分离:pthread_detach线程属性初始化:pthread_attr_init唯一执行:pthread_once,2006年4月,共享存储编程,11/108,同步对象,在共享存储多处理器并行机上,线程通过全局变量通信,对于全局变量的操作必须进行同步。
8、pthread提供两个线程同步原语 : 互斥和条件变量.,2006年4月,共享存储编程,12/108,互斥锁函数,函数 操作Mutex_init() 初始化一个互斥锁Mutext_lock() 阻塞式加锁操作Mutex_trylock() 非阻塞式加锁操作Mutex_unlock() 解锁Mutex_destroy() 解除互斥状态,2006年4月,共享存储编程,13/108,条件变量的函数,函数 操作pthread_cond_init() 初始化条件变量pthread_cond_wait() 阻塞直至条件为真pthread_cond_signal() 强制条件为真,解除等待条件的线程的阻塞p
9、thread_cond_timedwait()阻塞直到指定条件为真或timeoutpthread_cond_broadcast()解除所有等待条件的线程的阻塞pthread_cond _destroy() 销毁条件变量,2006年4月,共享存储编程,14/108,Hello World(1),#include #include stdio.hvoid *worker();main()pthread_t thread;pthread_create(,编译命令gcc hello.c lpthread运行结果Hello World!,2006年4月,共享存储编程,15/108,pthread_t 线
10、程数据类型pthread_create(当主进程执行exit()后,进程及其全部线程全部终止.,2006年4月,共享存储编程,16/108,pthread_join(pthread_t wait_for,void* status); 等待直到线程结束;执行该函数的线程发生阻塞,直到由wait_for指定的线程终止; 等与被等的两线程必须是同一进程内部的线程(而且不是分离线程);返回值0成功返回ESRCH参数wait_for指定的线程不存在或是一分离线程;EINVAL线程参数无效;EDEADLK 等待自身结束.不能有两个线程同时等待同一个线程的结束, 否则其中一个线程正常返回,另外一个返回ESR
11、CH错误.,2006年4月,共享存储编程,17/108,Hello World(2),#include #include stdio.h#define numthrds 5pthread_t *tid;void *worker();main()int i;tid = (pthread_t*) calloc(numthrds,sizeof(pthread_t);for(i=0;inumthrds;i+) pthread_create( ,Hello World from thread 0!Hello World from thread 1!Hello World from thread 2!He
12、llo World from thread 3!Hello World from thread 4!,2006年4月,共享存储编程,18/108,Hello World(3),#include #include stdio.h#define numthrds 5pthread_t *tid;pthread_mutex_t mutex;int sum=0;void *worker();main()int i;tid = (pthread_t*) calloc(numthrds,sizeof(pthread_t);pthread_mutex_init(,void *worker() int myi
13、d,num; myid = pthread_self() - tid0; printf(%d was added to the sum in thread %dn,myid*10,myid); pthread_mutex_lock(,2006年4月,共享存储编程,19/108,运行结果,0 was added to the sum in thread 010 was added to the sum in thread 120 was added to the sum in thread 230 was added to the sum in thread 340 was added to t
14、he sum in thread 4The sum is 100,2006年4月,共享存储编程,20/108,基于多线程编程的PI求解,2006年4月,共享存储编程,21/108,#include #include stdio.hpthread_mutex_t reduction_mutex;pthread_t *tid;double pi,w;int n;int num_threads;double f(a)double a; return (4.0/(1.0 + a*a);,void *PIworker(void* arg) int i,myid; double sum,mypi,x; /
15、*set individual id to start at 0 */ myid = pthread_self() - tid0; /*integrate function*/ sum=0.0; for(i = myid + 1;i = n; i+=num_threads) x = w * (double)i - 0.5); sum += f(x); mypi = w * sum; /*reduce value*/ pthread_mutex_lock(,2006年4月,共享存储编程,22/108,void main(argc,argv)int argc;char* argv; int i;
16、/*check command line */ if(argc != 3) printf(Usage: %s Num_intervals Num_threadsn,argv0); exit(0); /*get num intervals and num threads from command line*/ n = atoi(argv1); num_threads = atoi(argv2); w = 1.0 / (double)n; pi = 0.0; tid = (pthread_t*) calloc (num_threads,sizeof(pthread_t);,/*initilize
17、lock*/if(pthread_mutex_init(,gcc hello.c lpthread a.out 1000 5computed pi = 3.1415927369231271,转去Openmp,2006年4月,共享存储编程,23/108,多线程并行编程特点,pthread_create()创建一个新线程比重新启动一个线程花费的时间少: 需要时创建+任务结束立刻杀掉 vs. 维护一大堆的空闲线程并且相互切换.在加锁的前提下访问共享资源不支持数据并行,适合于任务级并行,即一个线程单独执行一个任务;不支持增量并行化,对于一个串行程序,很难用Pthreads进行并行化Pthreads主要
18、是面向操作系统, 而不是为高性能计算设计的,因此不是并行计算程序设计的主流平台。但是“多线程并发执行”这种思想却被广泛地应用于高性能计算。这就是我们即将要讲的共享存储并行编程的另外一种被并行机制造商和广用并行计算用户广泛接受的平台:OpenMP,2006年4月,共享存储编程,24/108,并行编程标准,线程库标准(Thread Library) Win32 API. POSIX threads线程模型. X3H5:概念性线程模型编译制导(Compiler Directives) OpenMP - portable shared memory parallelism.,2006年4月,共享存储编
19、程,25/108,www.openmp.org,An Industry Standard API for Shared Memory ProgrammingAn API for Writing Multithreaded Applications一系列编译制导语句和库函数使得Fortran, C and C+的多线程编程更加容易,2006年4月,共享存储编程,26/108,与X3H5的关系,X3H5是ANSI/X3授权的小组委员会,主要目的是在PCF(the Parallel Computing Forum)工作的基础上,发展并行计算的一个ANSI标准. PCF是一非正式的工业组织,虽在DO循
20、环的并行化方法的标准化方面做一些工作,但在起草拟了一个标准后就草草收场.OpenMP专门针对这类并行化问题,并完成了这项工作,同时得到工业界的广泛支持.,2006年4月,共享存储编程,27/108,ANSI X3H5共享编程标准,概念性的编程模型(ANSI标准(1993)没有任何商品化的共享存储器系统依附于X3H5,但X3H5的基本概念影响以后共享存储器系统的并行编程.(一些基本概念在OpenMP均出现!)X3H5支持C,Fortran77以及Fortran90语言.X3H5规定的基本的并行结构用于并行性表述:并行块(分散任务Work Sharing)并行循环单进程,parallel end
21、parallel,psections end psections,pdoend pdo,psingleend psingle,2006年4月,共享存储编程,28/108,X3H5编程实例,program main !程序以顺序模式执行A!A只由基本线程执行parallel!转换成并行模式B!B为每个组员所复制psections!并行块开始sectionC!一个组员执行CsectionD!另一个组员执行Dend psections!等待C和D都结束psingle暂时转换成顺序模式E!E只能被一个组员执行end psingle!转回并行模式pdo I=1,6!并行do循环开始F(i)!各线程分担循
22、环任务end pdo no wait!无隐式路障同步G!更多的复制代码end parallel!结束并行模式H!根进程执行H!更多的并行构造end,线程,P,Q,R,B,B,E,C,F(1:2),F(3:4),F(5:6),G,G,G,H,隐式barrier,隐式barrier,隐式barrier,无隐式barrier,隐式barrier,B,D,各线程以负载平衡方式分担任务可能为:F(1:1),F(2:2),F(3:6),2006年4月,共享存储编程,29/108,X3H5例程执行过程描述,程序以顺序方式启动,此时只有一个初始化线程,称为基本线程或主线程.当程序遇到parallel时,通过派
23、生多个子线程转换为并行执行模式(线程数隐式决定).基本线程与它的子线程形成一个组.所有组员并行处理后继并行代码,直至end parallel.然后程序转为顺序模式,只有基本线程继续执行.子线程遇到内部并行或任务分担构造时,可以继续派生其子线程,从而成为一个新组的基本线程.线程间同步,通信与交互隐式路障:parallel, end parallel, end pdo或end psingle处隐式barrier.如果不需,则加no wait;各处理机通过全局变量通信,通过私有变量封装数据,fork,.,barrier,顺序执行,顺序执行,并行执行,2006年4月,共享存储编程,30/108,Ope
24、nMP: 并行模型,Fork-Join 并行模式:主线程根据需要创建一组子线程进行工作分担.可对串行程序进行逐步并行化.,2006年4月,共享存储编程,31/108,如何应用OpenMP?,OpenMP常用于循环并行化: 找出最耗时的循环. 将循环由多线程完成.在串行程序上加上编译制导语句,完成并行化,因此可先完成串行程序,然后再进行OpenMP并行化.,void main() double Res1000; for(int i=0;i1000;i+) do_huge_comp(Resi); ,void main() double Res1000; #pragma omp parallel f
25、or for(int i=0;i1000;i+) do_huge_comp(Resi);,串行程序,并行程序,用OpenMP将该循环通过多线程进行任务分割,2006年4月,共享存储编程,32/108,线程间如何交互?,OpenMP 是基于共享内存模型.线程通过共享变量通信.访问共享变量会导致race condition (竞态状态)race condition:是一种状态,在这种状态下两个实体(例如两个处理过程)对同一资源进行竞争,而系统没有一种机制来测定首先要执行的是哪一个。因此,由于系统不能保证数据的正确处理,其结果是不可预测的。为了避免线程进入竞态状态:通过同步对象来保护数据冲突.,20
26、06年4月,共享存储编程,33/108,OpenMP术语,大多OpenMP构造是制导语句或pragmas.C和C+的pragmas形式为:#pragma omp construct clause clauseFortran中,制导语句形式为以下几种:C$OMP CONSTRUCT clause clause!$OMP CONSTRUCT clause clause(自由书写格式唯一)*$OMP CONSTRUCT clause clause例:以下三种等价(第一行为列数)C23456789!$OMP PARALLEL DO SHARED(A,B,C)C$OMP PARALLEL DOC$OMP
27、+SHARED(A,B,C)C$OMP PARALLELDOSHARED(A,B,C)由于OpenMP构造为注释性语句,因此一个OpenMP程序在用不支持OpenMP的编译器编译后,仍为串行程序.,2006年4月,共享存储编程,34/108,Structured blocks(结构化块),结构化块性质:仅在块顶有一个入口和块底有一个出口;块功能可通过构造的语法清晰地识别;块内除Fortran中的STOP语句和c/c+中的exit()语句外,不能有其它分支.大多OpenMP构造为结构化块.,C$OMP PARALLEL10 if() goto 10C$OMP END PARALLELprint
28、*,id,C$OMP PARALLEL10 30if() goto 20go to 10C$OMPEND PARALLELif() goto 3020print *, id,一个结构化块,一个非结构化块,2006年4月,共享存储编程,35/108,OpenMP结构化块类型,OpenMP主要有五类结构化块:并行区Parallel Regions任务分割Worksharing数据环境Data Environment同步Synchronization运行时函数/环境变量在Fortran,C/C+中,OpenMP基本上是一样的.,2006年4月,共享存储编程,36/108,Parallel Regio
29、ns(并行区),并行区是OpenMP的基本构造,并行区内的代码由各线程同时执行.当一个线程执行“omp parallel”后,建立一组线程,该线程成为新建立的线程组的主线程.所有线程构成一线程组,各线程以线程ID区分,主线程ID为0.线程组并行执行并行区内代码.如:建立一个4线程的并行区:,double A1000;omp_set_num_threads(4);#pragma omp parallel int ID = omp_thread_num(); worker(ID,A);,每一线程以不同的线程ID和相同的参数A执行并行区内代码的一拷贝.ID(=0,1,2,3).,2006年4月,共享
30、存储编程,37/108,并行区的Lecical / dynamic extent以及Orphaned 制所语句,bar.fsubroutine whoamiexternal omp_get_thread_numinteger iam, omp_get_thread_numiam = omp_get_thread_num()C$OMP CRITICALprint*,Hello from , iamC$OMP END CRITICALreturnend,poo.fC$OMP PARALLELcall whoamiC$OMP END PARALLEL,Static/lexical extent:在书
31、写上直接包含在并行区内的部分.,+,Dynamic extent:包括并行区内直接和间接(函数调用)包含的内容,也被称为region.,Orphan制导语句:落在子程序中的制导语句,方便于子程序的并行化,免去传统的inline处理,2006年4月,共享存储编程,38/108,并行区代码流程,double A1000;omp_set_num_threads(4);#pragma omp parallel int ID = omp_thread_num(); worker(ID,A);,opm_set_num_threads(4),worker(2,A),worker(1,A),worker(3,
32、A),Double A1000,worker(0,A),所有线程在此处同步(如,隐式barrier同步),每一线程执行相同代码,不同数据.,所以,并行区结构也被称为SPMD结构.,2006年4月,共享存储编程,39/108,Hello World(C),#include main() int myid,numthreads; #pragma omp parallel myid = omp_get_thread_num(); numthreads = omp_get_num_threads(); printf(Hello World from thread %d of %d!n,myid,num
33、threads); ,2006年4月,共享存储编程,40/108,Hello World(Fortran),PROGRAM HELLO integer myid,numthreads integer omp_get_num_threads,omp_get_thread_num!$omp parallel private(numthreads,myid) numthreads = omp_get_num_threads() myid = omp_get_thread_num() print *, Hello World from thread ,myid,of,numthreads!$omp e
34、nd parallel stop end,2006年4月,共享存储编程,41/108,OpenMP并行程序编译,支持编译OpenMP的编译器会提供编译器命令选项,以解释OpenMP编译制导语句.IBM AIX xlc编译器,编译器命令选项为-qsmpxlc file.c qsmpxlf_r file.f -qsmp (xlf_r为IBM AIX4.3为支持多线程编程的编译器)曙光3000:OS: AIX4.3 -qsmp AIX4.3支持 OpenMP编译选项Intel C/C+编译器icc, Intel Fortran编译器选项为-openmpicc file.c openmpifc fil
35、e.f openmp曙光4000L:OS:Redhat Linux 8.0PGI C/C+编译器icc, PGI Fortran编译器选项为-mppgcc file.c mppgf77 file.f mppgf90 file.f mp曙光4000A:OS:SuSE Linux 8.0 / Turbo Linux,2006年4月,共享存储编程,42/108,一些细节(可先不关心),C:#pragma omp parallel clause clause . new-linestructured-blockFortran:!$OMP PARALLEL clause, clause.block!$O
36、MP END PARALLEL子句clause是下列之一:if(expr):根据expr表达式执行结果决定是否并行执行private(list):变量私有化,默认为全部变量firstprivate(list):在并行区间之外引用变量首次赋值结果default(shared | none)(C)DEFAULT(PRIVATE | SHARED | NONE)(Fortran)shared(list):并行区间中的共享变量列表copyin(list):拷贝主线程的threadprivate公共区数据reduction(operator: list):归约操作,2006年4月,共享存储编程,43/1
37、08,OpenMP结构化块类型,OpenMP主要有五类结构化块:并行区Parallel Regions任务分割WorksharingDO(Fortran)/for(C)结构:针对循环的并行化结构Sections:代码段间的并行Single:强制并行区中某些代码以串行方式执行(如:I/O)数据环境Data Environment同步Synchronization运行时函数/环境变量,OpenMP最重要部分,2006年4月,共享存储编程,44/108,循环分割:DO(Fortran)/for(C)结构,Fortran!$OMP DO clause, clause.do_loop!$OMP END
38、DO NOWAIT(可选)C/C+#pragma omp for clause clause . new-linefor-loop,C$OMP PARALLELC$OMP DODO i=0,n ,#pragma omp parallel#pragma omp forfor (i=0;in;i+) ,在DO/for结构之后有一隐式barrier同步操作,用NO WAIT/no wait可以禁止.,2006年4月,共享存储编程,45/108,比较parrallel构造与for构造,for(i=0;IN;i+) ai = ai + bi;,#pragma omp parallel int id, i
39、, Nthrds, istart, iend; id = omp_get_thread_num(); Nthrds = omp_get_num_threads(); istart = id * N / Nthrds; iend = (id+1) * N / Nthrds; for(i=istart;Iiend;i+) ai = ai + bi;,#pragma omp parallel#pragma omp for schedule(static)for(i=0;IN;i+) ai = ai + bi;,串行代码,用并行区实现并行化,用任务分割构造实现并行化,对于DO结构与PARALLEL结构
40、的比较同理,且以后讨论若无特别说明均基于C描述.,2006年4月,共享存储编程,46/108,并行区与任务分割间的关系,并行区和任务分割是OpenMP两类基本的并行性构造;并行区中的代码对组内的各线程是可见的,也即并行区内的代码由各线程同时执行;任务分割与并行区不同,它是将一个整体任务按负载平衡的方式分配给各线程来互相配合完成.并行区是并行的先决条件,任务分割必须要与并行区一起使用才能生效;并行区构造为!omp parallel;任务分割构造有:do/for,section,和single三种.,2006年4月,共享存储编程,47/108,更详细的for语法,#pragma omp for c
41、lause clause . new-linefor-loopClause可是下列说明:private(list)firstprivate(list)lastprivate(list)reduction(operator: list)orderedschedule(kind, chunk_size)nowait,后面将详细说明,2006年4月,共享存储编程,48/108,更详细的DO语法,!$OMP DO clause, clause.do_loop!$OMP END DO NOWAITPRIVATE(list)FIRSTPRIVATE(list)LASTPRIVATE(list)REDUCT
42、ION(operator|intrinsic_procedure_name:list)SCHEDULE(type,chunk)ORDERED,2006年4月,共享存储编程,49/108,DO/for使用注意事项,循环体必须紧接在DO或for之后.For循环必须为一结构化块,且其执行不被break语句中断.在Fortran中,如果写上END DO制导语句,其必须要紧跟在DO循环的结束之后.循环变量必须为整形.Schedule, ordered,nowait子句只能出现一次.,2006年4月,共享存储编程,50/108,schedule,Schedule子名决定循环如何在各线程中进行分配:sche
43、dule(dynamic,chunk)各线程每次得到chunk_size大小的任务,执行完后继续取得任务,以此反复,直至任务完成(最后一任务可能会小于chunk_size).(任务池)当chunk_size未被指定时,默认为1.schedule(static,chunk)如果chunk_size被指定, 则各线程按线程号顺序每人每得chunk次的循环任务,如果任务不能一次平分掉,则分配循环进行.如果chunk_size未被指定,则各线程任务数即为循环数除以所用线程数的结果.schedule(guided,chunk)开始以一大的单位进行分配忆,逐渐减小到chunk指定的值.schedule(r
44、untime)分配方式与chunk值大小取决于环境变量OMP_SCHEDULE的设置.chunk以循环次数为单位.示意图见下页.,2006年4月,共享存储编程,51/108,Schedule示意图,Work pool,Work,.,.,.,.,Dynamic方式,Static方式,执行时间,Guided方式,Work,.,.,.,.,.,.,.,2006年4月,共享存储编程,52/108,适用条件,静态:适用于大部分情形.特点:各线程任务明确,在任务分配时无需同步操作.运行快的线程需等慢的线程为:动态:适用于任务数量可变或不确定的情形(如条件收敛循环).特点:各线程将要执行的任务不可预见,任务
45、分配需同步操作.Guided:线程异步到达for结构特点:首先到达的线程总是分得q=ceiling(n/p)次循环,然后n=max(n-q,p*k),循环分配,直到n=p*k为止.环境变量:无需重新编译程序,可根据原始输入数据的情况改变任务分配策略.,2006年4月,共享存储编程,53/108,NOWAIT子句(Fortran),C$OMP PARALLEL C$OMP DO do i=1,n a(i)= cos(a(i) enddoC$OMP END DOC$OMP DO do i=1,n b(i)=a(i)+b(i) enddoC$OMP END DOC$OMP END PARALLEL,C$OMP PARALLEL C$OMP DO do i=1,n a(i)= cos(a(i) enddoC$OMP END DO NOWAITC$OMP DO do i=1,n b(i)=a(i)+b(i) enddoC$OMP END DOC$OMP END PARALLEL,隐式BARRIER,No BARRIER,默认循环变量i为私有线程私有类型变量,END DO必须紧随enddo,可省略.,
Copyright © 2018-2021 Wenke99.com All rights reserved
工信部备案号:浙ICP备20026746号-2
公安局备案号:浙公网安备33038302330469号
本站为C2C交文档易平台,即用户上传的文档直接卖给下载用户,本站只是网络服务中间平台,所有原创文档下载所得归上传人所有,若您发现上传作品侵犯了您的权利,请立刻联系网站客服并提供证据,平台将在3个工作日内予以改正。