Two-Phase Termination
強制的に外部から終了するのではなく、終了要求だけ出しておいて自分で終了してもらうようにするパターン。
終了要求を出して(1段階目)、実際に終了する(2段階目)という2つの段階を経て終了するので、この名前が付いているらしい。
以下は増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編のサンプルを Boost.Thread を使って書いたコード。
Java には interrupt 機構があって簡単に実現できるのだけれども、boost1.34.1 の Boost.Thread にはそういう機能は無いので、boost::condition を使って無理矢理動かしてます。
ただし、boost1.35.0 以降の Boost.Thread には interrupt 機構があるので、それを使えばかなり便利になるはず。
countup_thread.h
#ifndef MTDP_TWO_PHASE_TERMINATION_COUNTUP_THREAD_H_INCLUDED #define MTDP_TWO_PHASE_TERMINATION_COUNTUP_THREAD_H_INCLUDED #include <boost/thread.hpp> #include "../thread_helper.h" namespace mtdp{ namespace two_phase_termination { class countup_thread { private: // カウンタの値 int counter_; // 終了要求が出されたら true bool shutdown_requested_; boost::mutex mutex_; boost::condition condition_; public: countup_thread() : counter_(0), shutdown_requested_(false) { } // 終了要求 void shutdown_request() { boost::mutex::scoped_lock lock(mutex_); shutdown_requested_ = true; condition_.notify_all(); } // 終了要求が出されたかどうかのテスト bool is_shutdown_requested() const { boost::mutex::scoped_lock lock(mutex_); return shutdown_requested_; } // 動作 void run() { try { while (!is_shutdown_requested()) { do_work(); } } catch (...) { do_shutdown(); throw; } do_shutdown(); } private: // 作業 void do_work() { counter_++; thread_helper::shared_cout("do_work: counter = " + to_string(counter_) + "\n"); boost::mutex::scoped_lock lock(mutex_); boost::xtime xt; boost::xtime_get(&xt, boost::TIME_UTC); xt.nsec += 500 * 1000 * 1000; condition_.timed_wait(lock, xt); } // 終了処理 void do_shutdown() { thread_helper::shared_cout("do_shutdown: counter = " + to_string(counter_) + "\n"); } }; }} #endif // MTDP_TWO_PHASE_TERMINATION_COUNTUP_THREAD_H_INCLUDED
main.cpp
#include <boost/thread.hpp> #include <boost/shared_ptr.hpp> #include <boost/bind.hpp> #include "countup_thread.h" #include "../thread_helper.h" namespace mtdp{ namespace two_phase_termination { void main() { thread_helper::shared_cout("main: BEGIN\n"); // スレッドの起動 boost::shared_ptr<countup_thread> t(new countup_thread()); boost::thread th(boost::bind(&countup_thread::run, t)); // 少し時間をあける thread_helper::sleep(10000); // スレッドの終了処理 thread_helper::shared_cout("main: shutdown_request\n"); t->shutdown_request(); thread_helper::shared_cout("main: join\n"); // スレッドの終了を待つ th.join(); thread_helper::shared_cout("main: END\n"); } }}