版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
OpenMP并行編程主講人:趙永華中科院計(jì)算機(jī)網(wǎng)絡(luò)信息中心超級(jí)計(jì)算中心OpenMP編程簡介OPenMP編程制導(dǎo)OpenMP庫函數(shù)OpenMP環(huán)境變量OpenMP計(jì)算實(shí)例
*2并行機(jī)體系結(jié)構(gòu)及通信機(jī)制〔回憶〕PVP:并行向量機(jī)共享變量、單地址空間、集中共享、UMASMP:共享存貯并行機(jī),它是由多個(gè)處理器通過交叉開關(guān)〔Crossbar〕或開關(guān)〔SWITCH〕與內(nèi)存互連。共享變量、單地址空間、集中共享、UMAMPP:分布式存貯并行機(jī),它是由稱為結(jié)點(diǎn)通過消息傳遞網(wǎng)絡(luò)互連而成。共享變量、多地址空間、分布非共享、NORMA*3DSM:分布共享存貯并行機(jī),它是由結(jié)點(diǎn)〔一般是SMP系統(tǒng)〕通過高速消息傳遞網(wǎng)絡(luò)互連而成。存貯系統(tǒng)物理上是分布的,各結(jié)點(diǎn)有自己獨(dú)立的尋址空間,然而在邏輯上存貯系統(tǒng)是共享的。共享變量、單地址空間、分布共享、NUMACluster(Now,Cow)群集系統(tǒng):將單個(gè)處理器,用Ethernet,Myrinet,Quadrics,Infiniband,Switch連結(jié)起來形成群集系統(tǒng)。將SMP結(jié)點(diǎn)用高速網(wǎng)連結(jié)起來。將DSM用高速網(wǎng)連結(jié)起來。共享變量、多地址空間、分布非共享、NORMA*4OpenMP編程簡介*5OpenMP簡介OpenMP是共享存儲(chǔ)體系結(jié)構(gòu)上的一個(gè)并行編程模型。適合于SMP共享內(nèi)存多處理系統(tǒng)和多核處理器體系結(jié)構(gòu)。起源于ANSIX3H5標(biāo)準(zhǔn)簡單、移植性好和可擴(kuò)展性等特點(diǎn)提供了支持Fortran、C/C++的API和標(biāo)準(zhǔn)由一組編譯制導(dǎo)、運(yùn)行時(shí)庫函數(shù)〔Run-Timeroutines〕和環(huán)境變量組成。工業(yè)標(biāo)準(zhǔn)DEC、Intel、IBM、HP、Sun、SGI等公司支持包括Linux、UNIX和NT等多種操作系統(tǒng)平臺(tái)
*6OpenMP并行編程模式OpenMP是基于線程的并行編程模型。OpenMP采用Fork-Join并行執(zhí)行方式:OpenMP程序開始于一個(gè)單獨(dú)的主線程〔MasterThread〕,然后主線程一直串行執(zhí)行,直到遇見第一個(gè)并行域(ParallelRegion),然后開始并行執(zhí)行并行域。其過程如下:Fork:主線程創(chuàng)立一個(gè)并行線程隊(duì)列,然后,并行域中的代碼在不同的線程上并行執(zhí)行;Join:當(dāng)并行域執(zhí)行完之后,它們或被同步或被中斷,最后只有主線程在執(zhí)行。*7OpenMP程序并行框架FORKJIONFORKJIONMasterthread并行域并行域*8串行局部串行局部串行局部簡單的”Hello,world”O(jiān)penMP并性程序
/*用OpenMP/C編寫HelloWorld代碼段*/#include<omp.h>intmain(intargc,char*argv[]){
intnthreads,tid;
intnprocs;
charbuf[32];
/*Forkateamofthreads*/
#pragmaompparallelprivate(nthreads,tid)
{
/*Obtainandprintthreadid*/
tid=omp_get_thread_num();
printf("Hello,worldfromOpenMPthread%d\n",tid);
/*Onlymasterthreaddoesthis*/
if(tid==0){
nthreads=omp_get_num_threads();
printf("Numberofthreads%d\n",nthreads);
}
}
return0;}*9
編譯執(zhí)行:
efc-openmp–oHelloWorldHelloWorld.c
./HelloWorld
運(yùn)行結(jié)果:
HelloWorldfromOpenMPthread2 HelloWorldfromOpenMPthread0 Numberofthreads4 HelloWorldfromOpenMPthread3 HelloWorldfromOpenMPthread1*10OpenMP程序結(jié)構(gòu)基于Fortran語言的OpenMP程序結(jié)構(gòu)PROGRAMPROG_NAMEINTEGERVAR1,VAR2,VAR3……….!$OMPPARALLELPRIVATE(VAR1,VAR2)SHARED(VAR3)……….
!$OMPEND
PARALLEL……END*11基于C/C++語言的OpenMP程序結(jié)構(gòu)
#include<omp.h>main(){intvar1,var2,var3;……..#pragmaompparallelprivate(var1,var2)shared(var3){………….}……………}
*12
OpenMP編譯制導(dǎo)*13OpenMP的并行化是通過使用嵌入到C/C++或Fortran源代碼中的編譯制導(dǎo)語句來實(shí)現(xiàn)。編譯制導(dǎo)是對程序設(shè)計(jì)語言的擴(kuò)展。支持并行區(qū)域、工作共享、同步等。支持?jǐn)?shù)據(jù)的共享和私有化。通過對串行程序添加制導(dǎo)語句實(shí)現(xiàn)并行化*14制導(dǎo)語句格式編譯制導(dǎo)語句由以下幾局部組成:制導(dǎo)標(biāo)識(shí)符〔!$OMP、#pragmaomp〕制導(dǎo)名稱〔parallel,DO/for,section等〕子句〔privated,shared,reduction,copyin等〕格式:制導(dǎo)標(biāo)識(shí)符制導(dǎo)名稱[Cluase,]*15編譯制導(dǎo)標(biāo)識(shí)〔sentinels〕制導(dǎo)是特殊的、僅用于特定編譯器的源代碼。制導(dǎo)由一個(gè)位于行首的標(biāo)識(shí)加以區(qū)分。OpenMP制導(dǎo)標(biāo)識(shí):Fortran:!$OMP(orC$OMPor*$OMP)C/C++:#pragma
omp*16并行域制導(dǎo)一個(gè)并行域就是一個(gè)能被多個(gè)線程并行執(zhí)行的程序段Fortran:!$OMPPARALLEL[clauses]BLOCK
!$OMPENDPARALLELC/C++:
#pragmaompparallel[clauses]{BLOCK}*17說明在并行域結(jié)尾有一個(gè)隱式同步〔barrier〕。子句〔clause〕用來說明并行域的附加信息。在Fortran語言中,子句間用逗號(hào)或空格分隔;C/C++子句間用空格分開。
*18并行域結(jié)構(gòu):例圖
ThreadsThreadsMasterthreadMasterthreadbarrierbarrierMasterthread*19shared和privated子句并行域內(nèi)的變量,可以通過子句說明為公有或私有;在編寫多線程程序時(shí),確定哪些數(shù)據(jù)的公有或私有非常重要:影響程序的性能和正確性Fortran:
SHARED(list)PRIVATE(list)DEFAULT(SHARED|PRIVATE|NONE)C/C++:
shared(list)private(list)default(shared|private|none)*20例:每個(gè)線程初始共享數(shù)組的一列!$OMPPARALLELDEFAULT(NONE〕,PRIVATE〔I,MYID),!$OMP&SHARED(a,n)myid=omp_get_thread_num()+1doi=1,na(i,myid)=1.0enddo!$OMPENDPARALLEL說明:如何決定哪些變量是共享哪些是私有?通常循環(huán)變量、臨時(shí)變量、寫變量一般是私有的;數(shù)組變量、僅用于讀的變量通常是共享的。默認(rèn)時(shí)為公有。i0231*21并行域結(jié)構(gòu):reduction子句歸約用來從相關(guān)的操作〔+,*,max或min等〕中產(chǎn)生一個(gè)單一值;OpenMP提供了reduction子句。Fortran:REDUCTION(op:list)C/C++:reduction(op:list)例子:將一組數(shù)值歸約求和sum=0;$OMPPARALLELREDUCTION(+:sum),PRIVATE(I,MYID)myid=omp_get_thread_num()+1doi=1,nsum=sum+a(i,myid)enddo$OMPENDPARALLEL說明:在reduction子句中,編譯器為每個(gè)線程創(chuàng)立變量sum的私有副本。當(dāng)循環(huán)完成后,將這些值加在一起并把結(jié)果放到原始的變量sum中;Reduction中的op操作必須滿足算術(shù)結(jié)合律和交換律。*22計(jì)算Pi值/*SerielCode*/staticlongnum_steps=100000;doublestep;voidmain(){ inti;doublex,pi,sum=0.0,start_time,end_time; step=1.0/(double)num_steps;start_time=clock(); for(i=1;i<=num_steps;i++){ x=(i-0.5)*step; sum=sum+4.0/(1.0+x*x); } pi=step*sum;end_time=clock();printf(“Pi=%f\nRunningtime\n”,pi,end_time-start_time);
}*23并行域并行〔SPMD并行模式〕include<omp.h>
staticlongnum_steps=100000;doublestep;#defineNUM_THREADS4voidmain(){ inti;doublepi,sum[NUM_THREADS],start_time,end_time;step=1.0/(double)num_steps;omp_set_num_threads(NUM_THREADS)start_time=omp_get_wtime();#pragmaompparallel{intid;doublex;id=omp_get_thraead_num();for(i=id,sum[id]=0.0;i<num_steps;i=i+NUM_THREADS){ x=(i+0.5)*step;sum[id]+=4.0/(1.0+x*x); }}for(i=0,pi=0.0;i<NUM_THREADS;i++)pi+=sum[i]*step;end_time=omp_get_wtime();printf(“Pi=%f\nRunningtime\n”,pi,end_time-start_time);}*24任務(wù)劃分并行制導(dǎo)
制導(dǎo)可以出現(xiàn)在并行域內(nèi)部,并說明任務(wù)如何在多個(gè)線程間分配,OpenMP任務(wù)劃分制導(dǎo)包括:并行DO/for循環(huán)制導(dǎo)并行SECTIONS制導(dǎo)SINGLE和MASTER制導(dǎo)其它制導(dǎo)*25并行DO/for循環(huán)制導(dǎo)并行DO/for循環(huán)制導(dǎo)用來將循環(huán)劃分成多個(gè)塊,并分配給各線程并行執(zhí)行。Fortran:!$OMPDO[clauses]DO循環(huán)!$OMPENDDOC/C++:#pragmaompfor[clauses]for循環(huán)說明:并行DO/for循環(huán)有時(shí)需要PRIVATE和FIRSTPRIVARE子句;循環(huán)變量是私有的。*26可以將并行域和DO/for制導(dǎo)結(jié)合成單一的簡單形式Fortran:!$OMPPARALLEL[clauses]
!$OMPDO[clauses]
循環(huán)體!$OMPENDDO
!$OMPENDPARALLEL合并后形式:!$OMPPARALLELDO[clauses]
循環(huán)體!$OMPENDPARALLELDO同樣地,C/C++:合并后形式
#pragmaompparallelfor[clauses]{
循環(huán)體
}*27并行DO/for循環(huán)制導(dǎo):調(diào)度子句SCHEDULE該子句給出迭代循環(huán)劃分后的塊大小和線程執(zhí)行的塊范圍Fortran:SCHEDULE〔kind[,chunksize]〕C/C++:schedule(kind[,chunksize]〕其中:kind為STATIC,DYNAMIC或RUNTIMEchunksize是一個(gè)整數(shù)表達(dá)式例如:!$OMPDOSCHEDULE〔DYNAMIC,4〕循環(huán)體!$OMPDO
*28子句說明schedule(STATIC[,chunksize]〕:省略chunksize,迭代空間被劃分成〔近似〕相同大小的區(qū)域,每個(gè)線程被分配一個(gè)區(qū)域;如果chunksize被指明,迭代空間被劃分為chunksize大小,然后被輪轉(zhuǎn)的分配給各個(gè)線程例如:假設(shè)線程數(shù)為4schudule(static)T0T1T2T3140schudule(static,4)T0T1T2T3T0T1T2T3T0T1140*29并行DO/for循環(huán)制導(dǎo):調(diào)度子句SCHEDULEschedule(DYNAMIC[,chunksize]〕:劃分迭代空間為chunksize大小的區(qū)間,然后基于先來先效勞方式分配給各線程;當(dāng)省略chunksize時(shí),其默認(rèn)值為1。schedule(GUIDED[,chunksize]〕類似于DYNAMIC調(diào)度,但區(qū)間開始大,然后迭代區(qū)間越來越少,循環(huán)區(qū)間的劃分是基于類似以下公式完成的〔不同的編譯系統(tǒng)可能不同〕:
其中N是線程個(gè)數(shù),Sk表示第k塊的大小,Rk是剩余下未被調(diào)度的循環(huán)迭代次數(shù)。chunksize說明最小的區(qū)間大小。當(dāng)省略chunksize時(shí),其默認(rèn)值為1。schedule(RUNTIME〕調(diào)度選擇延遲到運(yùn)行時(shí),調(diào)度方式取決于環(huán)境變量OMP_SCHEDULE的值,例如:exportOMP_SCHEDULE=DYNAMIC,4;使用RUNTIME時(shí),指明chunksize是非法的;*30使用for循環(huán)制導(dǎo)計(jì)算pi值#include<omp.h>#defineNUM_THREADS4staticlongnum_steps=100000;doublestep;voidmain(){ inti,id;doublex,pi,sum[NUM_THREADS]; step=1.0/(double)num_steps; omp_set_num_threads(NUM_THREADS)#pragmaompparallelprivate(x,id){id=omp_get_thread_num();sum[id]=0;#pragmaompfor for(i=id;i<num_steps;i++){ x=(i+0.5)*step; sum[id]+=4.0/(1.0+x*x); }} for(i=0,pi=0.0;i<NUM_THREADS;i++)pi+=sum[i]*step;}*31調(diào)度子句SCHEDULE例圖*32數(shù)據(jù)競爭問題下面的循環(huán)無法正確執(zhí)行:
#pragmaompparallelforfor(k=0;k<100;k++){x=array[k];
array[k]=do_work(x);}正確的方式:直接聲明為私有變量
#pragmaompparallelforprivate(x)for(k=0;k<100;k++){x=array[k];
array[k]=do_work(x);}在parallel結(jié)構(gòu)中聲明變量,這樣的變量是私有的。#pragmaompparallelforfor(k=0;k<100;k++){intx;x=array[k];
array[k]=do_work(x);}*33SECTIONS制導(dǎo):任務(wù)分配區(qū)任務(wù)分配區(qū)(work-sharingsections)可以使OpenMP編譯器和運(yùn)行時(shí)庫將應(yīng)用程序中標(biāo)出的結(jié)構(gòu)化塊〔block〕分配到并行區(qū)域的一組線程上Fortran:!$OMPSECTIONS[clauses][!$OMPSECTION]block[!$OMPSECTIONblock]…………!$OMPENDSECTIONSC/C++:$pragmasections[clauses]{[$pragmasection]block[$pragmasectionblock]…..}*34說明:各結(jié)構(gòu)化塊在各線程間并行執(zhí)行:結(jié)構(gòu)化塊的數(shù)量少于線程個(gè)數(shù)??;結(jié)構(gòu)化塊的數(shù)量大于線程個(gè)數(shù)??。sections制導(dǎo)可以帶有PRIVATE、FIRSTPRIVATE和其它子句;每個(gè)section必須包含一個(gè)結(jié)構(gòu)體。將并行域和SECTIONS制導(dǎo)結(jié)合成單一的簡單形式:Fortran:$OMPPARALLELSECTIONS[clauses]…….$OMPENDPARALLELSECTIONSC/C++:$pragmaparallelsections[clauses]…….$pragmaendparallelsections*35并行SECTIONS制導(dǎo):例句!$OMPPARALLEL
!$OMPDO
循環(huán)體!$OMPENDDO
!$OMPSECTIONS
!$OMPSECTIONcallinit(x)
!$OMPSECTIONcallinit(y)
!$OMPSECTIONcallinit(z)
!$OMPENDSECTIONS!$OMPENDPARALLEL假設(shè)有4個(gè)線程迭代塊1迭代塊2迭代塊3迭代塊4init(x)init(y)init(z)idle
*36SINGLE制導(dǎo)SINGLE制導(dǎo):Fortran:!OMPSINGLE[clauses]block!OMPENDSINGLEC/C++:#pragmaompsingle[clauses]{structureblock}說明:
結(jié)構(gòu)體代碼僅由一個(gè)線程執(zhí)行;并由首先執(zhí)行到該代碼的線程執(zhí)行;其它線程等待直至該結(jié)構(gòu)塊被執(zhí)行完例子#pragmaompparallel{setup(x);#pragmaompsingle{input(y);}work(x,y); }*37SINGLE制導(dǎo):例圖#pragmaompparallel{
setup(x);
#pragmaompsingle{input(y);}work(x,y);}
*38MASTER制導(dǎo)MASTER制導(dǎo)Fortran:!OMPMASTER[clauses]block!OMPENDMASTERC/C++:#pragmaompmaster[clauses]structureblock說明:結(jié)構(gòu)體代碼僅由主線程執(zhí)行;其它線程跳過并繼續(xù)執(zhí)行;通常用于I/O;*39BARRIER制導(dǎo)BARRIER是OpenMP用于線程同步的一種方法Fortran:!$OMPBARRIERC/C++:#pragmaompbarrier說明:在所有的線程到達(dá)之前,沒有線程可以提前通過一個(gè)barrier;在DO/FOR、SECTIONS和SINGLE制導(dǎo)后,有一個(gè)隱式barrier存在;要么所有線程遇到barrier;要么沒有線程遇到barrier,否那么會(huì)出現(xiàn)死鎖。*40例子!$OMPPARALLELPRIVATE(i,myid,neighb)myid=omp_get_thread_num()neighb=myid-1if(myid.eq.0)neighb=omp_get_num_threads()-1 ………a(myid)=a(myid)*3.5!$OMPBARRIERb(myid)=a(neighb)+c…………!$OMPENDPARALLEL*41使用帶reduction子句的for循環(huán)制導(dǎo)#include<omp.h>#defineNUM_THREADS4staticlongnum_steps=100000;doublestep;voidmain(){ inti,id;doublex,pi,sum,start_time,end_time; step=1.0/(double)num_steps; omp_set_num_threads(NUM_THREADS);start_time=omp_get_wtime();#pragmaompparallelprivate(x,id){id=omp_get_thread_num();sum[id]=0;#pragmaompfor
private(x)shared(sum)reductuion(+:sum) for(i=id;i<num_steps;i++){ x=(i+0.5)*step; sum+=4.0/(1.0+x*x); }}start_time=omp_get_wtime();pi=sum*step;
printf(“Pi=%f\nRunningtime\n”,end_time-start_time);}*42NOWAIT子句Nowait子句可以除去隱藏在循環(huán)、SECTIONS或并行區(qū)后的同步Fortran:!OMPDOdoloop!OMPENDDONOWAITC/C++:#pragmaompfornowaitforloopSECTIONS制導(dǎo)和SINGLE制導(dǎo)有類似形式說明:
使用NOWAIT時(shí)要特別小心,有可能導(dǎo)致不可確定的bug;*43在有些地方使用NOWAIT可能是好的代碼形式,并且顯式的使用BARRIERS例子:兩個(gè)循環(huán)間沒有依賴性!$OMPPARALLEL
!$OMPdodoj=1,n …….!$OMPENDDONOWAIT
!$OMPdodoj=1,n …….!$OMPENDDONOWAIT!OMPENDPARALLEL*44保存共享變量:CRITICAL制導(dǎo)CRITICAL〔臨界段〕可以保護(hù)共享變量的更新,防止數(shù)據(jù)競爭,制導(dǎo)內(nèi)的代碼段僅能有一個(gè)線程執(zhí)行Fortran:!$OMPCRITICAL[(name)]block!$OMPENDCRITICAL[(name)]C/C++:#pragmaompcritical[(name)]structureblock說明Critical制導(dǎo)在某一時(shí)刻僅能被一個(gè)線程執(zhí)行;*45Critical制導(dǎo)可用來保護(hù)對共享變量的修改;在Fortran中,前后兩個(gè)name必須一致;如果name被省略,一個(gè)空〔null〕的name被假定。例:下面使用了一個(gè)未命名的臨界段。#pragmaompcritical{if(max<new_value)max=new_value}下面使用了一個(gè)命名的臨界段。#pragmaompcritical(maxvalue){if(max<new_value)max=new_value}使用命名臨界段時(shí),應(yīng)用程序可以有多個(gè)臨界段*46
通過private子句和critical制導(dǎo)計(jì)算pi值#include<omp.h>staticlongnum_steps=100000;doublestep;#defineNUM_THREADS4voidmain(){ inti;doublex,sum,pi=0.0,start_time,end_time; step=1.0/(double)num_steps; omp_set_num_threads(NUM_THREADS)start_time=omp_get_wtime();#pragmaompparallelprivate(x,sum){id=omp_get_thread_num(); for(i=id,sum=0.0;i<num_steps;i=i+NUM_THREADS){ x=(i+0.5)*step;sum+=4.0/(1.0+x*x); }#pragmaompcritical pi+=sum;}end_time=omp_get_wtime();
printf(“Pi=%f\nRunningtime\n”,pi,end_time-start_time);}*47保存共享變量:ATOMIC制導(dǎo)ATOMIC編譯制導(dǎo)說明一個(gè)特殊的存儲(chǔ)單元只能原子的更新,而不允許讓多個(gè)線程同時(shí)去寫主要用來保證操作被平安的執(zhí)行。Fortran:!$OMPATOMICstatementC/C++:#pragmaompatomicstatement說明在fortran中,statement必須是以下形式之一:x=xopexpr、x=expropx、x=intr(x,expr)或x=intr(expr,x)。其中:op是+、-、*、/、.and.、.or.、.eqv.、或.neqv.之一;intr是MAX、min、IAND、IOR或IEOR之一。
*48在C/C++中,statement必須是以下形式之一:xbinop=expr、x++、x--、++x、或--xx。其中:binop是二元操作符:+、-、*、/、&、^、<<或>>之一。ATOMIC編譯指導(dǎo)的好處是允許并行的更新數(shù)組內(nèi)的不同元素;而使用臨界值時(shí)數(shù)組元素的更新是串行的;無論何時(shí),當(dāng)需要在更新共享存儲(chǔ)單元的語句中防止數(shù)據(jù)競爭,應(yīng)該先使用atomic,然后再使用臨界段。*49LOCK例程一個(gè)鎖是一個(gè)特殊的變量,它被一個(gè)線程設(shè)定,而別的線程僅能在設(shè)定鎖的線程解除鎖后才能設(shè)定鎖Fortran:SubroutineOMP_INIT_LOCK(VAR)SubroutineOMP_SET_LOCK(VAR)LOGICALFUNCTIONOMP_TEST_LOCK(VAR)SubroutineOMP_UNSET_LOCK(VAR)SubroutineOMP_DESTROY_LOCK(VAR)其中變量是一個(gè)作為地址的整數(shù)*50C/C++:#include<OMP.h>voidomp_init_lock(omp_lock_t*lock);voidomp_set_lock(omp_lock_t*lock);intomp_test_lock(omp_lock_t*lock);voidomp_unset_lock(omp_lock_t*lock);voidomp_detroy_lock(omp_lock_t*lock);*51例子callomp_init_lock(ilock)!$OMPPARALLELSHARED(ilock)...dowhile(.not.omp_test_lock(ilock))calldo_something_else()enddocallwork()callomp_unset_lock(ilock)...!$OMPENDPARALLEL
說明:鎖在使用前需要進(jìn)行初始化;不再使用時(shí)要解鎖。
*52FLUSH制導(dǎo)FLUSH語句是用來確保執(zhí)行中存儲(chǔ)器中的數(shù)據(jù)一致的同步點(diǎn)。保證一個(gè)變量從內(nèi)存中的讀/寫Fortran:!$OPMFLUSH[(list)]C/C++:#prgmaompflush[(list)]*53Run-Timeroutines*54運(yùn)行庫函數(shù)OpenMP標(biāo)準(zhǔn)定義了一個(gè)應(yīng)用程序編程接口來調(diào)用庫中的多個(gè)函數(shù)。有時(shí)需要得到線程數(shù)和線程號(hào),這在控制不同線程執(zhí)行不同的功能代碼時(shí)特別有用。得到線程隊(duì)列中的線程數(shù)Fortran:intergerfunctionOMP_GET_NUM_THREADS()C/C++:#include<omp.h>intomp_get_num_threads()
*55得到執(zhí)行線程的線程號(hào):Fortran:IntergerfunctionOMP_GET_THREAD_NUM()C/C++:#include<omp.h>intomp_get_thread_num()*56設(shè)定執(zhí)行線程的數(shù)量使用運(yùn)行庫函數(shù):
Fortran:routineOMP_SET_NUM_THREADS()C/C++:#include<omp.h>omp_set_num_threads()在制導(dǎo)語句中通過OMP_NUM_THREADS設(shè)定。
通過環(huán)境變量OMP_NUM_THREADS設(shè)定。*57時(shí)間函數(shù)returncurrentwallclocktime(relativetoarbitraryorigin)Fortran:DOUBLEPRECISIONFUNCTIONOMP_GET_WTIME()C/C++:doubleomp_get_wtime(void);returnclockprecisionFortran:DOUBLEPRECISIONFUNCTIONOMP_GET_WTICK()C/C++:doubleomp_get_wtick(void);*58OpenMP環(huán)境變量*59環(huán)境變量OpenMP提供了4個(gè)環(huán)境變量用來控制并行代碼的執(zhí)行
設(shè)定線程數(shù)環(huán)境變量:例如:
1.
OMP_NUM_THREADS:設(shè)定最大線程數(shù)。
setenvOMP_NUM_THREADS42.OMP_SCHEDULE:設(shè)定DO/for循環(huán)調(diào)度方式環(huán)境變量。
setevnOMP_SCHEDULE“DYNAMIC,4”
*60
3.OMP_DYNAMIC:確定是否動(dòng)態(tài)設(shè)定并行域執(zhí)行的線程數(shù),其值為FALSE或TRUE。
setevnOMP_DYNAMICTRUE4.OMP_NESTED:確定是否可以并行嵌套。setenvOMP_NESTEDTURE*61NUM_THREADS子句在OpenMP2.0(Fortran、C/C++)中提供了NUM_THREADS子句設(shè)定線程數(shù)。例子!$OMPPARALLELDONUM_THREADS(4)DOJ=1,NA(I,J)=B(I,J)!$OMPENDDO說明:在NUM_THREADS中提供的值將取代環(huán)境變量OMP_NUM_THREADS的值(或由omp_set_num_threads()設(shè)定的值)*62OpenMP并行注意的問題數(shù)據(jù)競爭問題;線程間同步;并行執(zhí)行的程序比例及其可擴(kuò)展性;共享內(nèi)存或偽共享內(nèi)存引起的訪存沖突;在DO/for循環(huán)中插入OpenMP指導(dǎo)前,首先要解決的問題是檢查并重構(gòu)熱點(diǎn)循環(huán),確保沒有循環(huán)迭代相關(guān);優(yōu)良的并行算法和精心調(diào)試是好的性能的保證,糟糕的算法即使使用手工優(yōu)化的匯編語言來實(shí)現(xiàn),也無法獲得好的性能;創(chuàng)立在單核或單處理器上出色運(yùn)行的程序同創(chuàng)立在多核或單處理器上出色運(yùn)行的程序是不同的;可以借助一些工具,例IntelVtuneTM性能分析工具,其提供了一個(gè)Intel線程監(jiān)測器。………*63實(shí)例1:蒙特卡羅算法利用蒙特卡羅算法計(jì)算半徑為1單元的球體體積:(下面為相應(yīng)的串行代碼)#include<stdio.h>#include<stdlib.h>#include<time.h>intmain(){longlongmax=10000000;longlongi,count=0;doublex,y,z,bulk,start_time,end_time;time_tt;start_time=clock();//產(chǎn)生以當(dāng)前時(shí)間開始的隨機(jī)種子
srand((unsigned)time(&t));
for(i=0;i<max;i++)
{x=rand();x=x/32767;y=rand();y=y/32767;z=rand();z=z/32767;if((x*x+y*y+z*z)<=1)count++;}bulk=8*(double(count)/max);end_time=clock();printf(”Spherebulkis%f\n“,bulk);printf(“Runningtimeis%f\n“,end_time-start_time);return0;}*64OpenMPParallelforwithareduction#include<stdio.h>#include<stdlib.h>#include<time.h>#include<omp.h>intmain(){longlongmax=10000000;longlongi,count=0;doublex,y,z,bulk,start_time,end_time;time_tt;start_time=omp_get_wtime();//產(chǎn)生以當(dāng)前時(shí)間開始的隨機(jī)種子
srand((unsigned)time(&t));
#pragmaompparallelforprivate(x,y,z)reduction(+:count)for(i=0;i<max;i++){x=rand();x=x/32767;y=rand();y=y/32767;z=rand();z=z/32767;if((x*x+y*y+z*z)<=1)count++;}bulk=8*(double(count)/max);end_time=omp_get_wtime();printf(”Spherebulkis%f\n“,bulk);printf(“Runningtimeis%f\n“,end_time-start_time);return0;}*65作業(yè)1.循環(huán)是否可以直接并行doi=2,na(i)=2*a(i-1)enddoix=basedoi=1,na(ix)=a(ix)*b(i)ix=ix+strideenddo
doi=1,nb(i)=(a(i)-a(i-1))*0.5
enddo*662.上機(jī)調(diào)試培訓(xùn)內(nèi)容中提供的求解pi的各OpenMP并行程序。3.編寫一個(gè)矩陣-向量相乘的OpenMP并行程序。4.分析critical、atomic、lock、flush的用法設(shè)定線程個(gè)數(shù)子句:num_threadsnum_threads子句用來指定并行域內(nèi)使用線程的個(gè)數(shù),隨后的其它并行域不受此影響。例:
#include"omp.h"#include"stdio.h“main()
{omp_set_num_threads(4);#pragmaompparallelnum_threads(2)
printf(“mytheadnumberis%d\n",omp_get_thread_num());
}num_threads子句的優(yōu)先權(quán)高于庫例程omp_set_num_threads和環(huán)境變量NMP_NUM_THREADS。x[0]=10;for(i=0;i<n;i++){for(j=1;i<4;j++)x[j]=i+x[j-1];y[i]=x[1]-x[3];}firstprivate子句該子句使并行域內(nèi)私有變量的初始值通過master線程的值初始化。格式:
firstprivate(變量列表)例:x[0]=10;#pragmaompparallelforprivate(j)firstprivate(x)for(i=0;i<n;i++){for(j=1;i<4;j++)x[j]=i+x[j-1];y[i]=x[1]-x[3];}lastprivate子句該子句將使得DO/for循環(huán)制導(dǎo)內(nèi)私有變量的最后值賦值給master線程的變量。#pragmaompparallelforprivate(j)lastprivate(x)for(i=0;i<n;i++){x[0]=1.0;for(j=1;i<4;j++)x[j]=x[j-1]*[i-1];sum_of_power=x[0]+x[1]+X[2]+X[3];}n_cube=x[3];for(i=0;i<n;i++){x[0]=1.0;for(j=1;i<4;j++)x[j]=x[j-1]*[i-1];sum_of_power=x[0]+x[1]+X[2]+X[3];}n_cube=x[3];改善并行循環(huán)性能處理循環(huán)中存在的
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- GB/T 18281.5-2024醫(yī)療保健產(chǎn)品滅菌生物指示物第5部分:低溫蒸汽甲醛滅菌用生物指示物
- 2024年年托育項(xiàng)目資金申請報(bào)告代可行性研究報(bào)告
- 酒店餐飲部食品安全與員工健康管理制度
- 中考加油演講稿600字(28篇)
- 《采購談判方案》課件
- 《修效用與需求》課件
- 《計(jì)量專業(yè)實(shí)務(wù)》課件
- 匯報(bào)課件:山區(qū)鄉(xiāng)土資源的創(chuàng)造性開發(fā)與利用
- 黑龍江省肇東一中2025屆高三(最后沖刺)語文試卷含解析
- 2025屆上海市徐匯區(qū)上海第四中學(xué)高三最后一卷語文試卷含解析
- 學(xué)校青年教師培養(yǎng)責(zé)任書
- 動(dòng)車組-動(dòng)車組的基本結(jié)構(gòu)及特點(diǎn)
- 中醫(yī)護(hù)理技術(shù)的質(zhì)量與安全管理
- 螺栓安裝施工方案
- YB-4001.1-2007鋼格柵板及配套件-第1部分:鋼格柵板(中文版)
- 2023年政府采購評(píng)審專家考試題庫
- 三戰(zhàn)課件(輿論戰(zhàn)、法律戰(zhàn)、心理戰(zhàn))
- 第12課+明朝的興亡-【中職專用】《中國歷史》(高教版2023基礎(chǔ)模塊)
- 統(tǒng)編版語文三年級(jí)上冊第三單元培優(yōu)試卷(含答案)
- 生產(chǎn)效率統(tǒng)計(jì)表
- 醫(yī)療機(jī)構(gòu)藥品自查報(bào)告(3篇)
評(píng)論
0/150
提交評(píng)論