Effective Modern C++ study group Item39

Takatoshi Kondo
Takatoshi KondoSoftware Engineer at OGIS-RI en OGIS-RI
Effective Modern C++ 勉強会
Item39
近藤 貴俊
2015/10/4 1
今回紹介するItem
• Item 39:Consider void futures for one-shot
event communication.
• ワンショットイベントにvoid futureを使うことを
考えてみよう。
2015/10/4 2
2015/10/4 3
std::condition_variable cv;
std::mutex m;
cv.notify_one();
Item39
...
{
std::unique_lock<std::mutex> lk(m);
cv.wait(lk);
...
}
...
イベント用条件変数
cvと一緒に使うmutex
cvを通してイベント通知
イベントを通知する側
イベントを受ける側
mutexをlock
ここで通知を待つ
イベントを受けての処理(mはlock中)
イベントを受けての処理(mはlock解除されている)
このコードには問題がある
2015/10/4 4
std::condition_variable cv;
std::mutex m;
cv.notify_one();
Item39
...
{
std::unique_lock<std::mutex> lk(m);
cv.wait(lk);
...
}
...
イベント用条件変数
cvと一緒に使うmutex
cvを通してイベント通知
イベントを通知する側
イベントを受ける側
mutexをlock
ここで通知を待つ
イベントを受けての処理(mはlock中)
イベントを受けての処理(mはlock解除されている)
問題その1
1
2
3
3 でブロックしてしまう
2015/10/4 5
std::condition_variable cv;
std::mutex m;
完了しておくべき処理A
cv.notify_one();
Item39
...
{
std::unique_lock<std::mutex> lk(m);
cv.wait(lk);
処理Aが完了していることを期待
}
...
イベント用条件変数
cvと一緒に使うmutex
イベントを通知する側
イベントを受ける側
ここで通知を待つ
問題その2 spurious wakeup
3
1
3 で処理Aが完了していない
2
3
Sprious wakeupとリオーダーは無関係
次ページで訂正
2015/10/4 6
std::condition_variable cv;
std::mutex m;
Item39
...
{
std::unique_lock<std::mutex> lk(m);
cv.wait(lk);
}
...
イベント用条件変数
cvと一緒に使うmutex
イベントを通知する側
イベントを受ける側
ここで通知を待つ
問題その2 spurious wakeup
1
1 でnotifyされていないのに、ブロックが解除される。
http://d.hatena.ne.jp/yohhoy/20120326/p1 参照
2015/10/4 7
Item39
...
{
std::unique_lock<std::mutex> lk(m);
cv.wait(lk);
...
}
cv.wait(lk,
[]{ return whether the event has occurred; });
イベントを受ける側
ラムダ式を引数に取るversionのwaitを使う
本当にイベントが発生したかどうか確認する。
発生していたらtrue
このアプローチの詳細は後述
その前に
2015/10/4 8
Item39
flag = true;
フラグを用いたポーリングベースのアプローチ
std::atomic<bool> flag(false); atomic変数
while(!flag);
イベント通知
イベントを受けての処理
・mutex不要
・whileループの前にフラグがセットされても問題ない
・spurious wakeupの問題も無い
・ループが回り続けるため、CPUリソースを消費する
そこで、条件変数とフラグベースアプローチを組み合わせる
イベントを受ける側
イベントを通知する側
2015/10/4 9
Item39
...
{
std::unique_lock<std::mutex> lk(m);
flag = true;
}
cv.notify_one();
{
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{ return flag; });
...
}
...
イベントを通知する側
ロックされた区間でフラグを設定
std::condition_variable cv;
std::mutex m;
bool flag(false); flag操作はmutexでロックされた区間で行われるので
atomicでなくてよい
条件変数でイベント通知
イベントを受ける側
本当にイベントが発生したかどうか確認する。
発生していたらtrue
問題は全て解決する がコードはそこそこ複雑
この例ではflagはglobal
よってキャプチャ不要
2015/10/4 10
Item39
p.set_value();
std::promise<void> p; voidのpromiseを準備
p.get_future().wait();
イベント通知
イベントを受けての処理
future/promiseを使ったアプローチ
イベントを待つ
2015/10/4 11
Item39
実際にスレッドを使ったコード
std::promise<void> p;
void react();
void detect()
{
std::thread t([]
{
p.get_future().wait();
react();
});
...
p.set_value();
...
t.join();
}
イベントを待つ側のスレッド
イベントを送る側のスレッド
イベントを受けての処理
tをunjoinableに Item37参照
この例ではpはglobal
よってキャプチャ不要
2015/10/4 12
Item39
future/promiseを使ったアプローチ
std::promise<void> p;
void react();
void detect()
{
ThreadRAII tr(
std::thread([]
{
p.get_future().wait();
react();
}),
ThreadRAII::DtorAction::join
);
...
p.set_value();
...
}
Item37のThreadRAIIを使えばシンプルに?
2015/10/4 13
Item39
future/promiseを使ったアプローチ
std::promise<void> p;
void react();
void detect()
{
ThreadRAII tr(
std::thread([]
{
p.get_future().wait();
react();
}),
ThreadRAII::DtorAction::join
);
...
p.set_value();
...
}
Item37のThreadRAIIを使えばシンプルに?
ここで例外が発生したら
2015/10/4 14
Item39
future/promiseを使ったアプローチ
std::promise<void> p;
void react();
void detect()
{
ThreadRAII tr(
std::thread([]
{
p.get_future().wait();
react();
}),
ThreadRAII::DtorAction::join
);
...
p.set_value();
...
}
Item37のThreadRAIIを使えばシンプルに?
ここで例外が発生したら スレッドは待ったまま
set_value()は呼ばれない
2015/10/4 15
Item39
future/promiseを使ったアプローチ
std::promise<void> p;
void react();
void detect()
{
ThreadRAII tr(
std::thread([]
{
p.get_future().wait();
react();
}),
ThreadRAII::DtorAction::join
);
...
p.set_value();
...
}
Item37のThreadRAIIを使えばシンプルに?
ここで例外が発生したら スレッドは待ったまま
set_value()は呼ばれない
ThreadRAIIのデストラクタでjoinするため、そこでブロックし、
ThreadRAIIのデストラクタが永久に終わらない
2015/10/4 16
Item39
future/promiseを使ったアプローチ
std::promise<void> p;
void react();
void detect()
{
ThreadRAII tr(
std::thread([]
{
p.get_future().wait();
react();
}),
ThreadRAII::DtorAction::join
);
{
scope_exit se([] {p.set_value();});
...
}
...
}
struct scope_exit {
scope_exit(std::function<void (void)> f)
: f_(std::move(f)) {}
~scope_exit(void) { f_(); }
private:
std::function<void (void)> f_;
};
http://melpon.org/wandbox/permlink/NdFo1yH7d9t0O2FL
2015/10/4 17
Item39
future/promiseを使ったアプローチ(スレッドが複数の場合)
std::promise<void> p;
void detect()
{
auto sf = p.get_future().share();
std::vector<std::thread> vt;
for (int i = 0; i < threadsToRun; ++i) {
vt.emplace_back([sf]{ sf.wait();
react(); });
}
...
p.set_value();
...
for (auto& t : vt) {
t.join();
}
}
std::shared_futureを使う
例外を検知して p.set_value()する処理は必要
2015/10/4 18
Item39
• シンプルなイベント通知を条件変数を用いて実現する場合、
mutexとイベントが発生したかのチェックが必要になる。
• この問題を回避するためにフラグを導入すれば良いが、
ポーリングベースだとブロックしない
• 条件変数とフラグを組み合わせは、
通知メカニズムを堅苦しいもの(stilted)にする
• std::promiseとfutureの組み合わせでこの問題を解決できる
が、shared stateのためのheap memoryを必要とし、また、一
度きりの通知にしか使えない
Things to Remember
1 de 18

Recomendados

続わかりやすいパターン認識8章 por
続わかりやすいパターン認識8章続わかりやすいパターン認識8章
続わかりやすいパターン認識8章Akiyoshi Hara
2.8K vistas75 diapositivas
続わかりやすいパターン認識7章 por
続わかりやすいパターン認識7章続わかりやすいパターン認識7章
続わかりやすいパターン認識7章Akiyoshi Hara
685 vistas24 diapositivas
Effective Modern C++勉強会#2 Item 11(,12) por
Effective Modern C++勉強会#2 Item 11(,12)Effective Modern C++勉強会#2 Item 11(,12)
Effective Modern C++勉強会#2 Item 11(,12)Keisuke Fukuda
1K vistas10 diapositivas
effective modern c++ chapeter36 por
effective modern c++ chapeter36effective modern c++ chapeter36
effective modern c++ chapeter36Tatsuki SHIMIZU
1K vistas22 diapositivas
emc++ chapter32 por
emc++ chapter32emc++ chapter32
emc++ chapter32Tatsuki SHIMIZU
1.1K vistas16 diapositivas
Effective modern C++ 勉強会 #3 Item 12 por
Effective modern C++ 勉強会 #3 Item 12Effective modern C++ 勉強会 #3 Item 12
Effective modern C++ 勉強会 #3 Item 12Keisuke Fukuda
2.4K vistas20 diapositivas

Más contenido relacionado

Destacado

Effective Modern C++ 勉強会 Item 22 por
Effective Modern C++ 勉強会 Item 22Effective Modern C++ 勉強会 Item 22
Effective Modern C++ 勉強会 Item 22Keisuke Fukuda
2.8K vistas15 diapositivas
Effective Modern C++ 勉強会#7 Item 27 por
Effective Modern C++ 勉強会#7 Item 27Effective Modern C++ 勉強会#7 Item 27
Effective Modern C++ 勉強会#7 Item 27Mitsuru Kariya
2K vistas71 diapositivas
Effective Modern C++ 勉強会#3 Item 15 por
Effective Modern C++ 勉強会#3 Item 15Effective Modern C++ 勉強会#3 Item 15
Effective Modern C++ 勉強会#3 Item 15Mitsuru Kariya
1.3K vistas59 diapositivas
Effective Modern C++ 勉強会 Item26 por
Effective Modern C++ 勉強会 Item26Effective Modern C++ 勉強会 Item26
Effective Modern C++ 勉強会 Item26Akihiro Nishimura
1.2K vistas18 diapositivas
Effective Modern C++ 勉強会#6 Item25 por
Effective Modern C++ 勉強会#6 Item25Effective Modern C++ 勉強会#6 Item25
Effective Modern C++ 勉強会#6 Item25Takashi Hoshino
2K vistas15 diapositivas
Effective Modern C++ 勉強会#8 Item38 por
Effective Modern C++ 勉強会#8 Item38Effective Modern C++ 勉強会#8 Item38
Effective Modern C++ 勉強会#8 Item38Takashi Hoshino
1.3K vistas12 diapositivas

Destacado(18)

Effective Modern C++ 勉強会 Item 22 por Keisuke Fukuda
Effective Modern C++ 勉強会 Item 22Effective Modern C++ 勉強会 Item 22
Effective Modern C++ 勉強会 Item 22
Keisuke Fukuda2.8K vistas
Effective Modern C++ 勉強会#7 Item 27 por Mitsuru Kariya
Effective Modern C++ 勉強会#7 Item 27Effective Modern C++ 勉強会#7 Item 27
Effective Modern C++ 勉強会#7 Item 27
Mitsuru Kariya2K vistas
Effective Modern C++ 勉強会#3 Item 15 por Mitsuru Kariya
Effective Modern C++ 勉強会#3 Item 15Effective Modern C++ 勉強会#3 Item 15
Effective Modern C++ 勉強会#3 Item 15
Mitsuru Kariya1.3K vistas
Effective Modern C++ 勉強会 Item26 por Akihiro Nishimura
Effective Modern C++ 勉強会 Item26Effective Modern C++ 勉強会 Item26
Effective Modern C++ 勉強会 Item26
Akihiro Nishimura1.2K vistas
Effective Modern C++ 勉強会#6 Item25 por Takashi Hoshino
Effective Modern C++ 勉強会#6 Item25Effective Modern C++ 勉強会#6 Item25
Effective Modern C++ 勉強会#6 Item25
Takashi Hoshino2K vistas
Effective Modern C++ 勉強会#8 Item38 por Takashi Hoshino
Effective Modern C++ 勉強会#8 Item38Effective Modern C++ 勉強会#8 Item38
Effective Modern C++ 勉強会#8 Item38
Takashi Hoshino1.3K vistas
Effective modern c++ 8 por uchan_nos
Effective modern c++ 8Effective modern c++ 8
Effective modern c++ 8
uchan_nos1.3K vistas
Effective Modern C++ Item 24: Distinguish universal references from rvalue re... por mooopan
Effective Modern C++ Item 24: Distinguish universal references from rvalue re...Effective Modern C++ Item 24: Distinguish universal references from rvalue re...
Effective Modern C++ Item 24: Distinguish universal references from rvalue re...
mooopan1.6K vistas
Effective Modern C++ 読書会 Item 35 por Keisuke Fukuda
Effective Modern C++ 読書会 Item 35Effective Modern C++ 読書会 Item 35
Effective Modern C++ 読書会 Item 35
Keisuke Fukuda11.1K vistas
Effective Modern C++勉強会#4 Item 17, 18資料 por Ryo Igarashi
Effective Modern C++勉強会#4 Item 17, 18資料Effective Modern C++勉強会#4 Item 17, 18資料
Effective Modern C++勉強会#4 Item 17, 18資料
Ryo Igarashi11.6K vistas
Effective modern c++ 5 por uchan_nos
Effective modern c++ 5Effective modern c++ 5
Effective modern c++ 5
uchan_nos11.4K vistas

Más de Takatoshi Kondo

CppCon2016 report and Boost.SML por
CppCon2016 report and Boost.SMLCppCon2016 report and Boost.SML
CppCon2016 report and Boost.SMLTakatoshi Kondo
1.4K vistas24 diapositivas
Pub/Sub model, msm, and asio por
Pub/Sub model, msm, and asioPub/Sub model, msm, and asio
Pub/Sub model, msm, and asioTakatoshi Kondo
1.6K vistas42 diapositivas
Boost sg msgpack por
Boost sg msgpackBoost sg msgpack
Boost sg msgpackTakatoshi Kondo
4K vistas49 diapositivas
MessagePack(msgpack): Compact and Fast Serialization Library por
MessagePack(msgpack): Compact and Fast Serialization LibraryMessagePack(msgpack): Compact and Fast Serialization Library
MessagePack(msgpack): Compact and Fast Serialization LibraryTakatoshi Kondo
5.4K vistas27 diapositivas
Boostsapporomsmpost 111106070819-phpapp02 por
Boostsapporomsmpost 111106070819-phpapp02Boostsapporomsmpost 111106070819-phpapp02
Boostsapporomsmpost 111106070819-phpapp02Takatoshi Kondo
662 vistas95 diapositivas
Boostsapporomsmpre 111030054504-phpapp02 por
Boostsapporomsmpre 111030054504-phpapp02Boostsapporomsmpre 111030054504-phpapp02
Boostsapporomsmpre 111030054504-phpapp02Takatoshi Kondo
443 vistas95 diapositivas

Más de Takatoshi Kondo(10)

CppCon2016 report and Boost.SML por Takatoshi Kondo
CppCon2016 report and Boost.SMLCppCon2016 report and Boost.SML
CppCon2016 report and Boost.SML
Takatoshi Kondo1.4K vistas
Pub/Sub model, msm, and asio por Takatoshi Kondo
Pub/Sub model, msm, and asioPub/Sub model, msm, and asio
Pub/Sub model, msm, and asio
Takatoshi Kondo1.6K vistas
MessagePack(msgpack): Compact and Fast Serialization Library por Takatoshi Kondo
MessagePack(msgpack): Compact and Fast Serialization LibraryMessagePack(msgpack): Compact and Fast Serialization Library
MessagePack(msgpack): Compact and Fast Serialization Library
Takatoshi Kondo5.4K vistas
Boostsapporomsmpost 111106070819-phpapp02 por Takatoshi Kondo
Boostsapporomsmpost 111106070819-phpapp02Boostsapporomsmpost 111106070819-phpapp02
Boostsapporomsmpost 111106070819-phpapp02
Takatoshi Kondo662 vistas
Boostsapporomsmpre 111030054504-phpapp02 por Takatoshi Kondo
Boostsapporomsmpre 111030054504-phpapp02Boostsapporomsmpre 111030054504-phpapp02
Boostsapporomsmpre 111030054504-phpapp02
Takatoshi Kondo443 vistas
Unpack mechanism of the msgpack-c por Takatoshi Kondo
Unpack mechanism of the msgpack-cUnpack mechanism of the msgpack-c
Unpack mechanism of the msgpack-c
Takatoshi Kondo3.4K vistas
Aho-Corasick string matching algorithm por Takatoshi Kondo
Aho-Corasick string matching algorithmAho-Corasick string matching algorithm
Aho-Corasick string matching algorithm
Takatoshi Kondo6.1K vistas

Effective Modern C++ study group Item39

  • 1. Effective Modern C++ 勉強会 Item39 近藤 貴俊 2015/10/4 1
  • 2. 今回紹介するItem • Item 39:Consider void futures for one-shot event communication. • ワンショットイベントにvoid futureを使うことを 考えてみよう。 2015/10/4 2
  • 3. 2015/10/4 3 std::condition_variable cv; std::mutex m; cv.notify_one(); Item39 ... { std::unique_lock<std::mutex> lk(m); cv.wait(lk); ... } ... イベント用条件変数 cvと一緒に使うmutex cvを通してイベント通知 イベントを通知する側 イベントを受ける側 mutexをlock ここで通知を待つ イベントを受けての処理(mはlock中) イベントを受けての処理(mはlock解除されている) このコードには問題がある
  • 4. 2015/10/4 4 std::condition_variable cv; std::mutex m; cv.notify_one(); Item39 ... { std::unique_lock<std::mutex> lk(m); cv.wait(lk); ... } ... イベント用条件変数 cvと一緒に使うmutex cvを通してイベント通知 イベントを通知する側 イベントを受ける側 mutexをlock ここで通知を待つ イベントを受けての処理(mはlock中) イベントを受けての処理(mはlock解除されている) 問題その1 1 2 3 3 でブロックしてしまう
  • 5. 2015/10/4 5 std::condition_variable cv; std::mutex m; 完了しておくべき処理A cv.notify_one(); Item39 ... { std::unique_lock<std::mutex> lk(m); cv.wait(lk); 処理Aが完了していることを期待 } ... イベント用条件変数 cvと一緒に使うmutex イベントを通知する側 イベントを受ける側 ここで通知を待つ 問題その2 spurious wakeup 3 1 3 で処理Aが完了していない 2 3 Sprious wakeupとリオーダーは無関係 次ページで訂正
  • 6. 2015/10/4 6 std::condition_variable cv; std::mutex m; Item39 ... { std::unique_lock<std::mutex> lk(m); cv.wait(lk); } ... イベント用条件変数 cvと一緒に使うmutex イベントを通知する側 イベントを受ける側 ここで通知を待つ 問題その2 spurious wakeup 1 1 でnotifyされていないのに、ブロックが解除される。 http://d.hatena.ne.jp/yohhoy/20120326/p1 参照
  • 7. 2015/10/4 7 Item39 ... { std::unique_lock<std::mutex> lk(m); cv.wait(lk); ... } cv.wait(lk, []{ return whether the event has occurred; }); イベントを受ける側 ラムダ式を引数に取るversionのwaitを使う 本当にイベントが発生したかどうか確認する。 発生していたらtrue このアプローチの詳細は後述 その前に
  • 8. 2015/10/4 8 Item39 flag = true; フラグを用いたポーリングベースのアプローチ std::atomic<bool> flag(false); atomic変数 while(!flag); イベント通知 イベントを受けての処理 ・mutex不要 ・whileループの前にフラグがセットされても問題ない ・spurious wakeupの問題も無い ・ループが回り続けるため、CPUリソースを消費する そこで、条件変数とフラグベースアプローチを組み合わせる イベントを受ける側 イベントを通知する側
  • 9. 2015/10/4 9 Item39 ... { std::unique_lock<std::mutex> lk(m); flag = true; } cv.notify_one(); { std::unique_lock<std::mutex> lk(m); cv.wait(lk, []{ return flag; }); ... } ... イベントを通知する側 ロックされた区間でフラグを設定 std::condition_variable cv; std::mutex m; bool flag(false); flag操作はmutexでロックされた区間で行われるので atomicでなくてよい 条件変数でイベント通知 イベントを受ける側 本当にイベントが発生したかどうか確認する。 発生していたらtrue 問題は全て解決する がコードはそこそこ複雑 この例ではflagはglobal よってキャプチャ不要
  • 10. 2015/10/4 10 Item39 p.set_value(); std::promise<void> p; voidのpromiseを準備 p.get_future().wait(); イベント通知 イベントを受けての処理 future/promiseを使ったアプローチ イベントを待つ
  • 11. 2015/10/4 11 Item39 実際にスレッドを使ったコード std::promise<void> p; void react(); void detect() { std::thread t([] { p.get_future().wait(); react(); }); ... p.set_value(); ... t.join(); } イベントを待つ側のスレッド イベントを送る側のスレッド イベントを受けての処理 tをunjoinableに Item37参照 この例ではpはglobal よってキャプチャ不要
  • 12. 2015/10/4 12 Item39 future/promiseを使ったアプローチ std::promise<void> p; void react(); void detect() { ThreadRAII tr( std::thread([] { p.get_future().wait(); react(); }), ThreadRAII::DtorAction::join ); ... p.set_value(); ... } Item37のThreadRAIIを使えばシンプルに?
  • 13. 2015/10/4 13 Item39 future/promiseを使ったアプローチ std::promise<void> p; void react(); void detect() { ThreadRAII tr( std::thread([] { p.get_future().wait(); react(); }), ThreadRAII::DtorAction::join ); ... p.set_value(); ... } Item37のThreadRAIIを使えばシンプルに? ここで例外が発生したら
  • 14. 2015/10/4 14 Item39 future/promiseを使ったアプローチ std::promise<void> p; void react(); void detect() { ThreadRAII tr( std::thread([] { p.get_future().wait(); react(); }), ThreadRAII::DtorAction::join ); ... p.set_value(); ... } Item37のThreadRAIIを使えばシンプルに? ここで例外が発生したら スレッドは待ったまま set_value()は呼ばれない
  • 15. 2015/10/4 15 Item39 future/promiseを使ったアプローチ std::promise<void> p; void react(); void detect() { ThreadRAII tr( std::thread([] { p.get_future().wait(); react(); }), ThreadRAII::DtorAction::join ); ... p.set_value(); ... } Item37のThreadRAIIを使えばシンプルに? ここで例外が発生したら スレッドは待ったまま set_value()は呼ばれない ThreadRAIIのデストラクタでjoinするため、そこでブロックし、 ThreadRAIIのデストラクタが永久に終わらない
  • 16. 2015/10/4 16 Item39 future/promiseを使ったアプローチ std::promise<void> p; void react(); void detect() { ThreadRAII tr( std::thread([] { p.get_future().wait(); react(); }), ThreadRAII::DtorAction::join ); { scope_exit se([] {p.set_value();}); ... } ... } struct scope_exit { scope_exit(std::function<void (void)> f) : f_(std::move(f)) {} ~scope_exit(void) { f_(); } private: std::function<void (void)> f_; }; http://melpon.org/wandbox/permlink/NdFo1yH7d9t0O2FL
  • 17. 2015/10/4 17 Item39 future/promiseを使ったアプローチ(スレッドが複数の場合) std::promise<void> p; void detect() { auto sf = p.get_future().share(); std::vector<std::thread> vt; for (int i = 0; i < threadsToRun; ++i) { vt.emplace_back([sf]{ sf.wait(); react(); }); } ... p.set_value(); ... for (auto& t : vt) { t.join(); } } std::shared_futureを使う 例外を検知して p.set_value()する処理は必要
  • 18. 2015/10/4 18 Item39 • シンプルなイベント通知を条件変数を用いて実現する場合、 mutexとイベントが発生したかのチェックが必要になる。 • この問題を回避するためにフラグを導入すれば良いが、 ポーリングベースだとブロックしない • 条件変数とフラグを組み合わせは、 通知メカニズムを堅苦しいもの(stilted)にする • std::promiseとfutureの組み合わせでこの問題を解決できる が、shared stateのためのheap memoryを必要とし、また、一 度きりの通知にしか使えない Things to Remember