fc2ブログ

[C++] boost::asio/futureを使ったActiveObjectパターンの実装

2013-04-16 | 17:40

[C++] boost::asio/futureを使ったActiveObjectパターンの実装

このページのActiveObjectの実装を一部修正して、日本語のコメントをつけてみた。

#include <boost/asio.hpp>
#include <boost/smart_ptr/make_shared.hpp>
#include <boost/thread.hpp>

class ActiveObject { 
    boost::asio::io_service scheduler_; 
    boost::asio::io_service::work work_; 
    boost::thread_group threads_; 

    public: 
    ActiveObject() : scheduler_(), work_(scheduler_), threads_() { 
        // io_serviceをスレッドで動かしておく
        threads_.create_thread( boost::bind(&boost::asio::io_service::run, &scheduler_) ); 
        std::cout << "scheduler started" << std::endl;
    }; 
    protected: 
    ~ActiveObject() { 
        scheduler_.stop(); 
        threads_.join_all(); 
    }; 
    template <typename T>
        boost::unique_future<int> schedule(T function) { 

            // futureを取得するために、ハンドラを元にpackaged_taskを作る
            typedef boost::packaged_task<int> task_t;
            boost::shared_ptr<task_t> task = boost::make_shared<task_t>(function);

            // futureを取得
            boost::unique_future<int> f = task->get_future();

            // io_serviceに処理をpost
            scheduler_.post(boost::bind(&task_t::operator(), task));
            std::cout << "posted" << std::endl;

            // futureを返す(postされた処理はまだ終了していない)
            return f;
        }; 
}; 

class Servant : public ActiveObject { 
    public:
        boost::unique_future<int> do_something(const std::string& str) { 
            // リクエストをスケジュールキューに入れる
            // (スケジューラによってリクエストがキューから取り出されたら Servant::do_something_impl()が実行される)
            return schedule(boost::bind(&Servant::do_something_impl, this, str));
        }; 
    private: 
        int do_something_impl(const std::string& str) { 
            boost::this_thread::sleep(boost::posix_time::milliseconds(3000));
            std::cout << str << std::endl;
            return 777;
        }; 
}; 

int main(){

    Servant s;

    // do_something()メソッドの呼び出し
    // 実際の処理は別スレッドで実行されるので呼び出し自体はすぐに終了する
    boost::unique_future<int> f = s.do_something("active object sample"); 

    // futureを待つ (スレッドが終了するのを待つ)
    std::cout << "wait for future" << std::endl;
    std::cout << f.get() << std::endl;

    return 0;
}  

packaged_taskをio_serviceにpost()する部分はここに説明がある。