Contenu connexe
Plus de Takashi Hoshino (16)
Effective Modern C++ 勉強会#8 Item38
- 3. Thread handles
• ここでは std::thread と std::future,
std::shared_future のこと
• std::future と std::shared_future はこの資料で
は合わせて future と呼ぶことにする
3
- 5. future の destructor
• 時には implicit join のように振る舞う
• 時には implicit detach のように振る舞う
• 時には何もしないように振る舞う
• 何故???
5
- 6. callee 結果の保存場所
• callee (promise)でも caller (future) 側でもない
• callee 側は先に destructor 呼ばれるケースあり
• caller 側は future が移動/共有されるケースあり
• future から参照され、参照カウントで管理され
る shared state に結果が書かれる
6
- 7. future destructor の振る舞い
• 条件A: std::async 由来の shared state を参照
• 条件B: ポリシが std::launch::async
• 条件C: 自分が shared state を参照する最後の
future
• 条件ABCを全て満たす場合、
block し、タスクの完了を待つ
• それ以外の場合、
単にリソースを開放する
7
- 8. 何故???
• 理由1: implicit detach は避けたかった
(Item 37 参照)
• 理由2: だからといって、std::thread のように
std::terminate を呼んでほしくなかった
(std::async は高級だから??)
• だから必要があれば implicit join することにした
• 色々と是非が議論された(らしい)が、C++11 から
C++14 においてはそのまま
8
- 9. future destructor の観察
9
int f() {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << “task end” << std::endl;
}
int main() {
{
std::packaged_task<int()> pt(f);
auto fut = pt.get_future();
#if 0
std::thread t(std::move(pt));
#elif 0
auto fut1 = std::async(std::launch::deferred, std::move(pt));
#elif 0
auto fut1 = std::async(std::launch::async, std::move(pt));
#endif
}
std::cout << “block end” << std::endl;
}
- 11. Item 38 Things to remember
• Future の destructor は通常単にメンバの
destructor を呼んでメモリ開放するだけである
• std::async non-deferred 呼び出し経由の
shared state を持つ最後の future destructor は
タスク完了を待つ (implicit join())
11
- 12. 感想
• deferred std::async
関数オブジェクトで良いのでは
• non-deferred std::async
promise/future 使ってくれる implicit join 機能付き
std::thread、しかも std::thread は誰かがよろしく管理
してくれる
• デフォルトポリシが std::launch::deferred |
std::launch::async って筋悪だと思う。
• よろしくスケジュールしてくれる(わけがない)
• どちらになったかで振る舞いが異なりすぎると思う
12