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()する部分はここに説明がある。