注:本文主要內(nèi)容摘自筆者所著的《多核計(jì)算與程序設(shè)計(jì)》一書,略有修改,后續(xù)還會繼續(xù)發(fā)布系列文章,如有需要,可以考慮將一下地址加入到您的瀏覽器收藏夾中: http://software.intel.com/zh-cn/blogs/category/multicore/ 。
從前面的 CNestTaskScheduler 的使用方法中可以發(fā)現(xiàn),采用嵌套任務(wù)調(diào)度,可以很方便地將一個大區(qū)間拆分成更多的小區(qū)間,將各個拆分后的區(qū)間放入分布式隊(duì)列中,然后各個線程再從分布式隊(duì)列中取出相應(yīng)的區(qū)間進(jìn)行處理。
對于一個 for 循環(huán)來說,通常處理的都是一個區(qū)間,因此也可以使用任務(wù)調(diào)度的方式將其拆分成更小的區(qū)間進(jìn)行并行化執(zhí)行。下面就利用嵌套任務(wù)調(diào)度的方法來實(shí)現(xiàn)一個 Parall_For 功能。
1. ??????? 區(qū)間的描述: CRange 類
要實(shí)現(xiàn)對區(qū)間的分拆功能,使用一個類 CRange 來描述區(qū)間。在實(shí)際情況中,區(qū)間通常可以由兩個整數(shù)表示區(qū)間開始和結(jié)束位置,也可以由兩個迭代器變量來表示區(qū)間開始和結(jié)束位置。不過 CRange 是一個抽象接口類,它并不定義區(qū)間的開始和結(jié)束位置,區(qū)間的開始和結(jié)束位置由繼承它的類去定義。 CRange 類用 C++ 定義如下:
class CRange {
protected:
??? CNestTaskScheduler ? * m_pTaskScheduler ;
public:
??? CRange (){};
??? CRange ( CNestTaskScheduler * p );
??? void SetTaskScheduler ( CNestTaskScheduler * p );
??? CNestTaskScheduler * GetTaskScheduler ();
?
??? virtual CRange * Split () = 0;
};
在 CRange 類中,最重要的一個接口是 Split() 接口,這個接口負(fù)責(zé)將一個區(qū)間拆分成兩個區(qū)間,一個區(qū)間繼續(xù)存放在原來的 CRange 對象中,另外一個區(qū)間存放在返回的 CRange 對象中。如果返回值為 NULL ,表明原來的區(qū)間不需要進(jìn)行分拆。
CRange 類本身是一個接口類,用它主要是作為 Parallel_For() 函數(shù)的接口函數(shù), Parallel_For() 函數(shù)的原型如下:
void Parallel_For(CRange *pRange );
由于 Split() 是一個純虛函數(shù),因此傳給 Parallel_For() 函數(shù)的參數(shù)必須是一個繼續(xù)了 CRange 類的派生類的實(shí)例。
2. ??????? 對 CRange 對象的處理過程
對于每個 CRange 對象, Parallel_For() 中需要對它進(jìn)行處理,處理是通過任務(wù)調(diào)度器中的任務(wù)入口函數(shù)來處理的,處理過程如下圖所示:
?
圖 4 ? CRange 對象的處理過程
上面的處理過程可以用 C++ 代碼實(shí)現(xiàn)如下:
/** ?? CRange 的任務(wù)處理入口函數(shù)
?
???????? @param ? void *pArg - 實(shí)際為一個 CRange 指針
???????? @return ? unsigned int WINAPI - CAPI_FAILED 表示失敗, CAPI_SUCCESS 表示成功 ??
*/
unsigned int WINAPI RangeProcessTask(void *pArg)
{
??? CRange * pRange = ( CRange *) pArg ;
?
??? if ( pRange == NULL )
??? {
??????? return CAPI_FAILED ;
??? }
?
??? CRange * pNewRange = pRange -> Split ();
??? if ( pNewRange == NULL )
??? {
??????? delete pRange ;
?????? ? return CAPI_SUCCESS ;
??? }
?
??? CNestTaskScheduler * pTaskSched = pRange -> GetTaskScheduler ();
?
??? pNewRange -> SetTaskScheduler ( pTaskSched );
?
??? TASK t1 , t2 ;
??? t1 . pArg = ( void *) pRange ;
??? t1 . func = RangeProcessTask ;
??? t2 . pArg = ( void *) pNewRange ;
?? ? t2 . func = RangeProcessTask ;
?
??? pTaskSched -> SpawnLocalTask ( t1 );
??? pTaskSched -> SpawnTask ( t2 );
?
??? return CAPI_SUCCESS ;
}
?
3. ? Parall_For 的處理流程
有了上面的 RangeProcessTask() 函數(shù)后,就可以用它作為嵌套任務(wù)調(diào)度器的任務(wù)入口函數(shù),以實(shí)現(xiàn) Parallel_For 功能。
在 Parallel_For() 中,主要實(shí)現(xiàn)對 CRange 對象的任務(wù)調(diào)度處理,需要將參數(shù) pRange 作為根任務(wù)傳入到任務(wù)調(diào)度器中進(jìn)行處理。
Parallel_For() 的處理過程如下:
?
圖 5 ? Parallel_For 的處理過程
Parallel_For() 的代碼如下:
/** ?? 并行 for 循的處理函數(shù)
??? 將一個 CRange 進(jìn)行并行處理
?
???????? @param ? CRange *pRange - CRange 指針 ????
???????? @return ? void - 無 ?
*/
void Parallel_For(CRange *pRange )
{
??? CNestTaskScheduler ? * p = new CNestTaskScheduler ;
??? TASK ??? task ;
?
??? task . func = RangeProcessTask ;
??? task . pArg = pRange ;
?
??? pRange -> SetTaskScheduler ( p );
?
??? p -> BeginRootThread ( task );
?
??? delete p ;
}
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

