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");
   }
}}