OPENMP?SECTIONS?CONSTRUCT原理示例解析
前言
在本篇文章當(dāng)中主要給大家介紹 OpenMP 當(dāng)中主要給大家介紹 OpenMP 當(dāng)中 sections construct 的實(shí)現(xiàn)原理以及他調(diào)用的動(dòng)態(tài)庫(kù)函數(shù)分析。如果已經(jīng)了解過(guò)了前面的關(guān)于 for 的調(diào)度方式的分析,本篇文章就非常簡(jiǎn)單了。
編譯器角度分析
在這一小節(jié)當(dāng)中我們將從編譯器角度去分析編譯器會(huì)怎么處理 sections construct ,我們以下面的 sections construct 為例子,看看編譯器是如何處理 sections construct 的。
#pragma omp sections
{
#pragma omp section
stmt1;
#pragma omp section
stmt2;
#pragma omp section
stmt3;
}
上面的代碼會(huì)被編譯器轉(zhuǎn)換成下面的形式,其中 GOMP_sections_start 和 GOMP_sections_next 是并發(fā)安全的,他們都會(huì)返回一個(gè)數(shù)據(jù)表示第幾個(gè) omp section 代碼塊,其中 GOMP_sections_start 的參數(shù)是表示有幾個(gè) omp section 代碼塊,并且返回給線程一個(gè)整數(shù)表示線程需要執(zhí)行第幾個(gè) section 代碼塊,這兩個(gè)函數(shù)的意義不同的是在 GOMP_sections_start 當(dāng)中會(huì)進(jìn)行一些數(shù)據(jù)的初始化操作。當(dāng)兩個(gè)函數(shù)返回 0 的時(shí)候表示所有的 section 都被執(zhí)行完了,從而退出 for 循環(huán)。
for (i = GOMP_sections_start (3); i != 0; i = GOMP_sections_next ())
switch (i)
{
case 1:
stmt1;
break;
case 2:
stmt2;
break;
case 3:
stmt3;
break;
}
GOMP_barrier ();
動(dòng)態(tài)庫(kù)函數(shù)分析
事實(shí)上在函數(shù) GOMP_sections_start 和函數(shù) GOMP_sections_next 當(dāng)中調(diào)用的都是我們之前分析過(guò)的函數(shù) gomp_iter_dynamic_next ,這個(gè)函數(shù)實(shí)際上就是讓線程始終原子指令去競(jìng)爭(zhēng)數(shù)據(jù)塊(chunk),這個(gè)特點(diǎn)和 sections 需要完成的語(yǔ)意是相同的,只不過(guò) sections 的塊大?。╟hunk size)都是等于 1 的,因?yàn)橐粋€(gè)線程一次只能夠執(zhí)行一個(gè) section 代碼塊。
unsigned
GOMP_sections_start (unsigned count)
{
// 參數(shù) count 的含義就是表示一共有多少個(gè) section 代碼塊
// 得到當(dāng)線程的相關(guān)數(shù)據(jù)
struct gomp_thread *thr = gomp_thread ();
long s, e, ret;
// 進(jìn)行數(shù)據(jù)的初始化操作
// 將數(shù)據(jù)的 chunk size 設(shè)置等于 1
// 分割 chunk size 的起始位置設(shè)置成 1 因?yàn)楦鶕?jù)上面的代碼分析 0 表示退出循環(huán) 因此不能夠使用 0 作為分割的起始位置
if (gomp_work_share_start (false))
{
// 這里傳入 count 作為參數(shù)的原因是需要設(shè)置 chunk 分配的最終位置 具體的源代碼在下方
gomp_sections_init (thr->ts.work_share, count);
gomp_work_share_init_done ();
}
// 如果獲取到一個(gè) section 的執(zhí)行權(quán) gomp_iter_dynamic_next 返回 true 否則返回 false
// s 和 e 分別表示 chunk 的起始位置和終止位置 但是在 sections 當(dāng)中需要注意的是所有的 chunk size 都等于 1
// 這也很容易理解一次執(zhí)行一個(gè) section 代碼塊
if (gomp_iter_dynamic_next (&s, &e))
ret = s;
else
ret = 0;
return ret;
}
// 下面是部分 gomp_sections_init 的代碼
static inline void
gomp_sections_init (struct gomp_work_share *ws, unsigned count)
{
ws->sched = GFS_DYNAMIC;
ws->chunk_size = 1; // 設(shè)置 chunk size 等于 1
ws->end = count + 1L; // 因?yàn)橐还灿?count 個(gè) section 塊
ws->incr = 1; // 每次增長(zhǎng)一個(gè)
ws->next = 1; // 從 1 開(kāi)始進(jìn)行 chunk size 的分配 因?yàn)?0 表示退出循環(huán)(編譯器角度分析)
}
unsigned
GOMP_sections_next (void)
{
// 這個(gè)函數(shù)就比較容易理解了 就是獲取一個(gè) chunk 拿到對(duì)應(yīng)的 section 的執(zhí)行權(quán)
long s, e, ret;
if (gomp_iter_dynamic_next (&s, &e))
ret = s;
else
ret = 0;
return ret;
}
// 下面的函數(shù)在之前的很多文章當(dāng)中都分析過(guò)了 這里不再進(jìn)行分析
// 下面的函數(shù)的主要過(guò)程就是使用 CAS 指令不斷的進(jìn)行嘗試,直到獲取成功或者全部獲取完成 沒(méi)有 chunk 需要分配
bool
gomp_iter_dynamic_next (long *pstart, long *pend)
{
struct gomp_thread *thr = gomp_thread ();
struct gomp_work_share *ws = thr->ts.work_share;
long start, end, nend, chunk, incr;
end = ws->end;
incr = ws->incr;
chunk = ws->chunk_size;
if (__builtin_expect (ws->mode, 1))
{
long tmp = __sync_fetch_and_add (&ws->next, chunk);
if (incr > 0)
{
if (tmp >= end)
return false;
nend = tmp + chunk;
if (nend > end)
nend = end;
*pstart = tmp;
*pend = nend;
return true;
}
else
{
if (tmp <= end)
return false;
nend = tmp + chunk;
if (nend < end)
nend = end;
*pstart = tmp;
*pend = nend;
return true;
}
}
start = ws->next;
while (1)
{
long left = end - start;
long tmp;
if (start == end)
return false;
if (incr < 0)
{
if (chunk < left)
chunk = left;
}
else
{
if (chunk > left)
chunk = left;
}
nend = start + chunk;
tmp = __sync_val_compare_and_swap (&ws->next, start, nend);
if (__builtin_expect (tmp == start, 1))
break;
start = tmp;
}
*pstart = start;
*pend = nend;
return true;
}
總結(jié)
在本篇文章當(dāng)中主要介紹了 OpenMP 當(dāng)中 sections 的實(shí)現(xiàn)原理和相關(guān)的動(dòng)態(tài)庫(kù)函數(shù)分析,關(guān)于 sections 重點(diǎn)在編譯器會(huì)如何對(duì) sections 的編譯指導(dǎo)語(yǔ)句進(jìn)行處理的,動(dòng)態(tài)庫(kù)函數(shù)和 for 循環(huán)的動(dòng)態(tài)調(diào)度方式是一樣的,只不過(guò) chunk size 設(shè)置成 1,分塊的起始位置等于 1,分塊的最終值是 section 代碼塊的個(gè)數(shù),最終在動(dòng)態(tài)調(diào)度的方式使用 CAS 不斷獲取 section 的執(zhí)行權(quán),指導(dǎo)所有的 section 被執(zhí)行完成。
更多精彩內(nèi)容合集可訪問(wèn)項(xiàng)目:github.com/Chang-LeHun…
以上就是OPENMP SECTIONS CONSTRUCT原理示例解析的詳細(xì)內(nèi)容,更多關(guān)于OPENMP SECTIONS CONSTRUCT 的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C++小知識(shí):不要節(jié)約代碼行數(shù)
今天小編就為大家分享一篇關(guān)于C++小知識(shí):不要節(jié)約代碼行數(shù),小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-01-01
C++實(shí)現(xiàn)LeetCode(36.驗(yàn)證數(shù)獨(dú))
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(36.驗(yàn)證數(shù)獨(dú)),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07
C++ std::condition_variable 條件變量用法解析
condition_variable(條件變量)是 C++11 中提供的一種多線程同步機(jī)制,它允許一個(gè)或多個(gè)線程等待另一個(gè)線程發(fā)出通知,以便能夠有效地進(jìn)行線程同步,這篇文章主要介紹了C++ std::condition_variable 條件變量用法,需要的朋友可以參考下2023-09-09
C++基于人工智能搜索策略解決農(nóng)夫過(guò)河問(wèn)題示例
這篇文章主要介紹了C++基于人工智能搜索策略解決農(nóng)夫過(guò)河問(wèn)題,簡(jiǎn)單描述了農(nóng)夫過(guò)河問(wèn)題的概念、實(shí)現(xiàn)原理并結(jié)合具體實(shí)例形式給出了C++使用人工智能搜索策略解決農(nóng)夫過(guò)河問(wèn)題的相關(guān)操作技巧,需要的朋友可以參考下2017-12-12
C++利用PCL點(diǎn)云庫(kù)操作txt文件詳解
這篇文章主要為大家詳細(xì)介紹了C++如何利用PCL點(diǎn)云庫(kù)操作txt文件,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解一下2024-01-01
C語(yǔ)言中的內(nèi)存泄露 怎樣避免與檢測(cè)
堆經(jīng)常會(huì)出現(xiàn)兩種類(lèi)型的問(wèn)題:1.釋放或改寫(xiě)仍在使用的內(nèi)存(稱(chēng)為:“內(nèi)存損壞”)。2.未釋放不再使用的內(nèi)存(稱(chēng)為:“內(nèi)存泄露”)。這是最難被調(diào)試發(fā)現(xiàn)的問(wèn)題之一2013-09-09
c語(yǔ)言中的二級(jí)指針做函數(shù)參數(shù)說(shuō)明
這篇文章主要介紹了c語(yǔ)言中的二級(jí)指針做函數(shù)參數(shù)說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05

