effective modern c++ 勉強会#8 item38

12
Effective Modern C++ 勉強会#8 Item 38 星野 喬(@starpoz) サイボウズ・ラボ 2015-08-19 1

Upload: takashi-hoshino

Post on 12-Apr-2017

642 views

Category:

Software


2 download

TRANSCRIPT

Effective Modern C++勉強会#8 Item 38

星野喬(@starpoz)

サイボウズ・ラボ

2015-08-19

1

Item 38Be aware of varying thread handle destructor behavior.

2

Thread handles

•ここでは std::thread と std::future, std::shared_future のこと

• std::future と std::shared_future はこの資料では合わせて future と呼ぶことにする

3

std::thread destructor

• joinable である場合、std::terminate が呼ばれてプロセス停止

• implicit join/detach を避けた(Item 37 参照)

4

future の destructor

•時には implicit join のように振る舞う

•時には implicit detach のように振る舞う

•時には何もしないように振る舞う

•何故???

5

callee 結果の保存場所

• callee (promise)でも caller (future) 側でもない• callee 側は先に destructor 呼ばれるケースあり

• caller 側は future が移動/共有されるケースあり

• future から参照され、参照カウントで管理される shared state に結果が書かれる

6

future destructor の振る舞い

•条件A: std::async 由来の shared state を参照

•条件B: ポリシが std::launch::async

•条件C: 自分が shared state を参照する最後のfuture

•条件ABCを全て満たす場合、block し、タスクの完了を待つ

•それ以外の場合、単にリソースを開放する

7

何故???

• 理由1: implicit detach は避けたかった(Item 37 参照)

• 理由2: だからといって、std::thread のようにstd::terminate を呼んでほしくなかった(std::async は高級だから??)

• だから必要があれば implicit join することにした

• 色々と是非が議論された(らしい)が、C++11 からC++14 においてはそのまま

8

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;

}

std::sync の返り値を受けなかった場合

• std::launch::deferred 結果を受けとる手段がないので永遠に実行されない。

• std::launch::async その場で future が destructor が呼ばれ、imlicit join によってタスク完了を待つ

10eratta comments

Item 38 Things to remember

• Future の destructor は通常単にメンバのdestructor を呼んでメモリ開放するだけである

• std::async non-deferred 呼び出し経由のshared state を持つ最後の future destructor はタスク完了を待つ (implicit join())

11

感想

• deferred std::async関数オブジェクトで良いのでは

• non-deferred std::asyncpromise/future 使ってくれる implicit join 機能付きstd::thread、しかも std::thread は誰かがよろしく管理してくれる

• デフォルトポリシが std::launch::deferred | std::launch::async って筋悪だと思う。• よろしくスケジュールしてくれる(わけがない)

• どちらになったかで振る舞いが異なりすぎると思う

12