国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設計 > 正文

基于OpenMP的多核DSP編程方法

2019-11-06 06:02:12
字體:
來源:轉載
供稿:網(wǎng)友
OpenMP是一種API,用于編寫可移植的多線程應用程序,無需程序員進行復雜的線程創(chuàng)建、同步、負載平衡和銷毀工作。使用OpenMP的好處:   1)CPU核數(shù)擴展性問題   2)方便性問題   3)可移植性問題OpenMP指令和庫函數(shù)介紹:   在C/C++中,OpenMP指令使用的格式為:#PRagma omp 指令 [子句[子句]…]   用法詳見OpenMP編程指南。2.#pragma omp parallel for       for(i=0;i<length;i++)       {           //沒有循環(huán)迭代相關的語句,如把圖像數(shù)組中的RGB值轉為灰度值。       }3.對可以以多線程執(zhí)行的循環(huán)的約束:1)循環(huán)變量必須是有符號整型,如果是無符號整型,就無法使用2)比較操作必須是<,>,<=,>=3)循環(huán)步長必須是整數(shù)加或整數(shù)減操作,加減的操作必須是一個不變量4)如果是<,<=,循環(huán)變量的值每次迭代時必須增加,否則減小5)循環(huán)內(nèi)部不允許有能夠到達循環(huán)之外的跳轉語句,也不允許有外部的跳轉語句到達循環(huán)內(nèi)部。exit語句例外,goto 和break的跳轉范圍必須在循環(huán)內(nèi)部,異常處理也必須在循環(huán)內(nèi)部處理4.數(shù)據(jù)相關(以下假設為語句S2與語句S1存在數(shù)據(jù)相關):相關的種類(相關不等于循環(huán)迭代相關):1)流相關:S1先寫某一存儲單元,而后S2又讀該單元2)輸出相關:兩個語句寫同一存儲單元3)反相關:一個語句先讀一單元,然后另一語句寫該單元相關產(chǎn)生的方式:1)S1在循環(huán)的一次迭代中訪問存儲單元L,S2在隨后的一次迭代中訪問L(是循環(huán)迭代相關)2)S1和S2在同一循環(huán)迭代中訪問同一存儲單元L,但S1的執(zhí)行在S2之前。(非循環(huán)迭代相關)5.數(shù)據(jù)競爭:      數(shù)據(jù)競爭可能是由于輸出相關引起的,編譯器不會進行數(shù)據(jù)競爭的檢測,Intel線程檢測器可以檢測數(shù)據(jù)競爭。用類似于互斥量的機制進行私有化和同步,可以消除數(shù)據(jù)競爭。#pragma omp parallel for private(x)       for(i=0;i<80;i++)       {         x=sin(i);         if(x>0.6)x=0.6;         printf("sin(%d)=%f/n",i,x);        }6.管理共享數(shù)據(jù)和私有數(shù)據(jù):private:每個線程都擁有該變量的一個單獨的副本,可以私有的訪問         1)private:說明列表中的每個變量對于每個線程都應該有一個私有副本。這個私有副本用變量的默認值進行初始化         2)firstprivate:見13數(shù)據(jù)的Copy-in 和Copy-out         3)lastprivate:見13數(shù)據(jù)的Copy-in 和Copy-out         4)reduction:         5)threadprivate:指定由每個線程私有的全局變量有三種方法聲明存儲單元為私有:         1)使用private,firstprivate,lastprivate,reduction子句         2)使用threadprivate         3)在循環(huán)內(nèi)聲明變量,并且不使用static關鍵字shared:所有線程都能夠訪問該單元,并行區(qū)域內(nèi)使用共享變量時,如果存在寫操作,必須對共享變量加以保護default:并行區(qū)中所有變量都是共享的,除下列三種情況下:          1)在parallel for循環(huán)中,循環(huán)索引時私有的。          2)并行區(qū)中的局部變量是私有的          3)所有在private,firstprivate,lastprivate,reduction子句中列出的變量是私有的7.循環(huán)調(diào)度與分塊     為了提供一種簡單的方法以便能夠在多個處理器之間調(diào)節(jié)工作負載,OpenMP給出了四種調(diào)度方案:static,dynamic,runtime,guided.     默認情況下,OpenMP采用靜態(tài)平均調(diào)度策略,但是可以通過調(diào)用schedule(kind[,chunksize])子句提供循環(huán)調(diào)度信息如:#pragma omp for schedule (kind[,chunk-size])   //chunk-size為塊大小guided根據(jù)環(huán)境變量里的設置來進行對前三種的調(diào)度在windows環(huán)境中,可以在”系統(tǒng)屬性|高級|環(huán)境變量”對話框中進行設置環(huán)境變量。8.有效地使用歸約:sum=0;for(k=0;k<100;k++){    sum=sum+func(k);}     為了完成這種形式的循環(huán)計算,其中的操作必須滿足算術結合律和交換律,同時sum是共享的,這樣循環(huán)內(nèi)部都可以加給這個變量,同時又必須是私有的,以避免在相加時的數(shù)據(jù)競爭。reduction子句可以用來有效地合并一個循環(huán)中某些關于一個或多個變量的滿足結合律的算術歸約操作。reduction子句主要用來對一個或多個參數(shù)條目指定一個操作符,每個線程將創(chuàng)建參數(shù)條目的一個私有拷貝,在區(qū)域的結束處,將用私有拷貝的值通過指定的運行符運算,原始的參數(shù)條目被運算結果的值更新。sum=0;#pragma omp parallel for reduction(+:sum)for(k=0;k<100;k++){    sum=sum+func(k);}9.降低線程開銷:當編譯器生成的線程被執(zhí)行時,循環(huán)的迭代將被分配給該線程,在并行區(qū)的最后,所有的線程都被掛起,等待共同進入下一個并行區(qū)、循環(huán)或結構化塊。              如果并行區(qū)域、循環(huán)或結構化塊是相鄰的,那么掛起和恢復線程的開銷就是沒必要的。舉例如下:                #pragma omp parallel //并行區(qū)內(nèi)                {                   #pragma omp for // 任務分配for循環(huán)                          for(k=0;k<m;k++){                               fun1(k);                           }                   #pragma omp for                          for(k=0;k<m;k++){                               fun2(k);                           }                }10.任務分配區(qū):     現(xiàn)實中應用程序的所有性能敏感的部分不是都在一個并行區(qū)域內(nèi)執(zhí)行,所以OpenMP用任務分配區(qū)這種結構來處理非循環(huán)代碼。任務分配區(qū)可以指導OpenMP編譯器和運行時庫將應用程序中標示出的結構化塊分配到用于執(zhí)行并行區(qū)域的一組線程上。舉例如下:              #pragma omp parallel //并行區(qū)內(nèi)                {                   #pragma omp for // 任務分配for循環(huán)                          for(k=0;k<m;k++){                               fun1(k);                           }                   #pragma omp sections private(y,z)                     {                           #pragme omp section//任務分配section                               {y=sectionA(x);}                           #pragme omp section                               {z=sectionB(x);}                     }                                   }11.使用Barrier和Nowait:      柵障(Barrier)是OpenMP用于線程同步的一種方法。線程遇到柵障是必須等待,直到并行區(qū)中的所有線程都到達同一點。注意:在任務分配for循環(huán)和任務分配section結構中,我們已經(jīng)隱含了柵障,在parallel,for,sections,single結構的最后,也會有一個隱式的柵障。隱式的柵障會使線程等到所有的線程繼續(xù)完成當前的循環(huán)、結構化塊或并行區(qū),再繼續(xù)執(zhí)行后面的工作。可以使用nowait去掉這個隱式的柵障去掉隱式柵障,例如:                #pragma omp parallel //并行區(qū)內(nèi)                {                   #pragma omp for nowait // 任務分配for循環(huán)                          for(k=0;k<m;k++){                               fun1(k);                           }                   #pragma omp sections private(y,z)                     {                           #pragme omp section//任務分配section                               {y=sectionA(x);}                           #pragme omp section                               {z=sectionB(x);}                     }                                   }     因為第一個 任務分配for循環(huán)和第二個任務分配section代碼塊之間不存在數(shù)據(jù)相關。加上顯示柵障,例如:                              #pragma omp parallel shared(x,y,z) num_threads(2)//使用的線程數(shù)為2                               {                                   int tid=omp_get_thread_num();                                   if(tid==0)                                       y=fun1();//第一個線程得到y(tǒng)                                   else                                         z=fun2();//第二個線程得到z                                   #pragma omp barrier //顯示加上柵障,保證y和z在使用前已有值                                   #pragma omp for                                           for(k=0;k<100;k++)                                                   x[k]=y+z;                               }12.單線程和多線程交錯執(zhí)行:      當開發(fā)人員為了減少開銷而把并行區(qū)設置的很大時,有些代碼很可能只執(zhí)行一次,并且由一個線程執(zhí)行,這樣單線程和多線程需要交錯執(zhí)行舉例如下:               #pragma omp parallel //并行區(qū)              {                    int tid=omp_get_thread_num();//每個線程都調(diào)用這個函數(shù),得到線程號                     //這個循環(huán)被劃分到多個線程上進行                      #pragma omp for nowait                      for(k=0;k<100;k++)                            x[k]=fun1(tid);//這個循環(huán)的結束處不存在使所有線程進行同步的隱式柵障                    #pragma omp master                      y=fn_input_only(); //只有主線程會調(diào)用這個函數(shù)                    #pragma omp barrier   //添加一個顯示的柵障對所有的線程同步,從而確保x[0-99]和y處于就緒狀態(tài)                     //這個循環(huán)也被劃分到多個線程上進行                    #pragma omp for nowait                      for(k=0;k<100;k++)                         x[k]=y+fn2(x[k]); //這個線程沒有柵障,所以不會相互等待                     //一旦某個線程執(zhí)行完上面的代碼,不需要等待就可以馬上執(zhí)行下面的代碼                     #pragma omp single //注意:single后面意味著有隱式barrier                     fn_single_print(y);                      //所有的線程在執(zhí)行下面的函數(shù)前會進行同步                     #pragma omp master                     fn_print_array(x);//只有主線程會調(diào)用這個函數(shù)              } 13.數(shù)據(jù)的Copy-in 和Copy-out:      在并行化一個程序的時候,一般都必須考慮如何將私有變量的初值復制進來(Copy-in ),以初始化線程組中各個線程的私有副本。在并行區(qū)的最后,還要將最后一次迭代/結構化塊中計算出的私有變量復制出來(Copy-out),復制到主線程中的原始變量中。firstprivate:使用變量在主線程的值對其在每個線程的對應私有變量進行初始化。一般來說,臨時私有變量的初值是未定義的。lastprivate:可以將最后一次迭代/結構化塊中計算出來的私有變量復制出來,復制到主線程對應的變量中,一個變量可以同時用firstprivate和lastprivate來聲明。copyin:將主線程的threadprivate變量的值復制到執(zhí)行并行區(qū)的每個線程的threadprivate變量中。copyprivate:使用一個私有變量將某一個值從一個成員線程廣播到執(zhí)行并行區(qū)的其他線程。該子句可以關聯(lián)single結構(用于single指令中的指定變量為多個線程的共享變量),在所有的線程都離開該結構中的同步點之前,廣播操作就已經(jīng)完成。14.保護共享變量的更新操作:     OpenMP支持critical和atomic編譯指導,可以用于保護共享變量的更新,避免數(shù)據(jù)競爭。包含在某個臨界段且由atomic編譯指導所標記的代碼塊可能只由一個線程執(zhí)行。例如:#pragma omp critical   {              if(max<new_value) max=new_value;         }15.OpenMP庫函數(shù)(#include <omp.h>):int omp_get_num_threads(void); //獲取當前使用的線程個數(shù)int omp_set_num_threads(int NumThreads);//設置要使用的線程個數(shù)int omp_get_thread_num(void);//返回當前線程號int omp_get_num_procs(void);//返回可用的處理核個數(shù)16.   編譯OpenMP要需要一個支持OpenMP的編譯器和線程安全的運行時庫。vs2005的配置屬性C/C++語言里提供對OpenMP的支持。   編譯時假如出現(xiàn)"沒有找到vcompd.dll,因此這個應用程序未能啟動。重新安裝應用程序可能會修復此問題",可能的原因是該項目有可能是從VC移植過來的,如果由VS創(chuàng)建,一般不會出現(xiàn)該問題,因為VS會解決在清單文件的調(diào)用dll問題。解決方法如下:StdAfx.h中加入 #pragma comment(linker, "/"/manifestdependency:type='Win32' name='Microsoft.VC80.DebugOpenMP' version='8.0.50608.0' processorArchitecture='X86' publicKeyToken='1fc8b3b9a1e18e3b' language='*'/"") 或者在Linker -> Manifest File -> Additional Manifest Dependencies -> 中加入:"type='Win32' name='Microsoft.VC80.DebugOpenMP' version='8.0.50608.0' processorArchitecture='X86' publicKeyToken='1fc8b3b9a1e18e3b' language='*'"
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 威信县| 台东县| 阳朔县| 确山县| 扎囊县| 慈溪市| 淮阳县| 色达县| 修水县| 鄂温| 巧家县| 甘南县| 互助| 小金县| 巢湖市| 东乡县| 天水市| 清河县| 新密市| 七台河市| 银川市| 道真| 山丹县| 阳朔县| 海伦市| 乐都县| 南丰县| 永宁县| 宁陵县| 简阳市| 邢台市| 榆中县| 武威市| 新泰市| 石楼县| 贵溪市| 湄潭县| 县级市| 湘潭市| 苍梧县| 昆明市|