[心得] C++17 execution policy

作者: Caesar08 (Caesar)   2016-05-16 20:30:43
C++17對不少現有的function提供parallel版本,例如:
std::copy, std::find, std::sort, std::unique...
(但有些function沒有,例如:std::sort_heap, std::copy_backward...)
要怎麼使用這些parallel function,就得了解本文要介紹的execution policy
execution policy目前分成3種class,分別是
std::sequential_execution_policy,
std::parallel_execution_policy,
std::parallel_vector_execution_policy
而在namespace std裡,已經有這3個class的object,分別是
std::sequential, std::par, std::par_vec
(關係如同std::defer_lock_t與std::defer_lock)
因此使用上,直接使用這3個object就可以
接下來將介紹不用execution policy的for_each,以及使用execution policy的for_each
(底下的std::就不打了)
vector<int> vec{1,2};
const auto func{[](const auto val){
cout<<val;
cout<<val;
}};
不用execution policy:
for_each(cbegin(vec),cend(vec),func);
執行結果:
1122
用sequential_execution_policy:
for_each(sequential,cbegin(vec),cend(vec),func);
執行結果可能是:
1122
2211
用sequential_execution_policy,表示func不一定會按照順序執行
但同一時間,絕對不會有2個func被執行(所以不用避免data race)
用parallel_execution_policy:
for_each(par,cbegin(vec),cend(vec),func);
執行結果可能是:
1122(由1個或2個thread執行的結果)
1212(由2個thread執行的結果)
1221(由2個thread執行的結果)
2112(由2個thread執行的結果)
2121(由2個thread執行的結果)
2211(由1個或2個thread執行的結果)
用parallel_execution_policy時,要避免data race的問題
到這邊為止,以上兩個都很正常,然而parallel_vector_execution_policy就比較特別了
用parallel_vector_execution_policy:
for_each(par_vec,cbegin(vec),cend(vec),func);
執行結果跟parallel_execution_policy一樣,但是多增加4種可能的結果
對於1212, 1221, 2112, 2121,他們有可能是由1個thread執行的結果
也就是說,當這個thread執行完func的第一個cout<<val;時
他可能會跳去執行別的func的code(!?)
這邊就要說一下code執行的順序
一般來說,在同個thread底下,給予2個evaluation,A與B
要不就是A先執行,之後換B;不然就是B先執行,之後換A
然而,使用parallel_vector_execution_policy時,就會產生另一種情況
就是A先執行,然後A還沒執行完,就跳去執行B(這情況叫做unsequenced)
也就是說,1212的執行結果由來可能是
main thread(呼叫for_each的thread)執行第一個func
main thread執行cout<<val;
main thread跳到第二個func
main thread執行cout<<val;(第二個func的第一個cout<<val;)
main thread跳回第一個func
main thread執行cout<<val;(第一個func的第二個cout<<val;)
main thread跳到第二個func
main thread執行cout<<val;(第二個func的第二個cout<<val;)
因此在用parallel_vector_execution_policy時,要非常小心,舉例來說:
mutex mut;
for_each(par_vec,cbegin(vec),cend(vec),[&](const auto val){
lock_guard<mutex> lock{mut};
cout<<val;
});
當第一個func執行完lock_guard<mutex> lock{mut};後
他可能會跳到另一個func,然後又執行lock_guard<mutex> lock{mut};
此時就會發生undefined behavior
結語:
雖然以上講了那麼多,但是目前還沒有compiler支援execution policy
所以各位可能還要等一段時間,才能使用這些特性了
註:
有些補充擺到另一篇文章了(#1NEeDZ3X)
作者: descent (「雄辯是銀,沉默是金」)   2016-05-16 22:04:00
感謝分享
作者: IKAFIRE (沒有)   2016-05-16 22:32:00
par_vec的用途是什麼?
作者: x000032001 (版廢了該走了)   2016-05-16 23:02:00
func的宣告好酷喔 XD 可以問一下關鍵字嗎
作者: loveflames (咕啾咕啾魔法陣)   2016-05-16 23:19:00
func是lambda啊
作者: x000032001 (版廢了該走了)   2016-05-16 23:43:00
主要是那對 {} 的用法 搭上const auto 蠻有js的感覺
作者: holydc (のヮの)   2016-05-17 00:19:00
看起來 sequential 就滿像 js interpreter 的 policy
作者: IKAFIRE (沒有)   2016-05-17 01:37:00
呃,我是問那個policy的用途是什麼,什麼情況下會用到呢

Links booklink

Contact Us: admin [ a t ] ucptt.com