「Boost.Contextの使い道がわからない」という声をちらほら聞くので、ちょっと実用的なサンプル。
わかりやすいのがリアルタイムゲームだと思ったので、ゲームループ(1/60秒での定期実行)で少しずつファイルを読んでいく処理を書きました。これと同じようにして、シューティングゲームやパチンコなどでの弾道なんかにも使えますね。
【a.txt】
aaa bbb ccc
#include <iostream> #include <fstream> #include <boost/bind.hpp> #include <boost/ref.hpp> #include <boost/asio.hpp> #include <boost/asio/steady_timer.hpp> #include "continuation.hpp" namespace asio = boost::asio; namespace chrono = boost::chrono; class Game { std::vector<std::string> data; continuation cont; public: Game() : cont(boost::bind(&Game::load_file, this)) { } void update() { if (!cont.is_complete()) { cont.resume(); std::cout << data.back() << std::endl; } } void draw() { } private: void load_file() { std::ifstream file("a.txt"); std::string line; while (std::getline(file, line)) { data.push_back(line); if (file.peek() != EOF) { cont.suspend(); } } } }; const chrono::milliseconds timer_duration(static_cast<int>(1.0 / 60.0 * 1000)); void on_timer(Game& game, asio::steady_timer& timer) { game.update(); game.draw(); timer.expires_from_now(timer_duration); timer.async_wait( boost::bind(&on_timer, boost::ref(game), boost::ref(timer))); } int main() { Game game; asio::io_service io_service; asio::steady_timer timer(io_service); timer.expires_from_now(timer_duration); timer.async_wait( boost::bind(&on_timer, boost::ref(game), boost::ref(timer))); io_service.run(); }
aaa bbb ccc
ここでは、fstreamの変数をローカル変数にして、Boost.Contextでsuspendしてスタックを保存し、次回呼ばれたときにfstreamの変数が前回呼ばれた状態から再開するようにしてます。
continuationクラスは、このブログで何回か使ってきたので省略します。ファイルリソースの破棄をする必要があるので、stack_unwindにしてデストラクタが自動的に呼ばれるようにしてます。
追記 2012/03/13 11:14
継続(Boost.Context)を使わなかった場合:
#include <iostream> #include <fstream> #include <boost/bind.hpp> #include <boost/ref.hpp> #include <boost/asio.hpp> #include <boost/asio/steady_timer.hpp> #include <boost/utility/value_init.hpp> namespace asio = boost::asio; namespace chrono = boost::chrono; class Game { std::vector<std::string> data; std::ifstream file; boost::initialized<bool> is_loaded; public: void update() { if (!is_loaded.data()) { load_file(); std::cout << data.back() << std::endl; } } void draw() { } private: void load_file() { if (is_loaded.data()) { return; } if (!file.is_open()) { file.open("a.txt"); } std::string line; if (!std::getline(file, line)) { is_loaded.data() = true; file.close(); return; } data.push_back(line); if (file.peek() == EOF) { is_loaded.data() = true; file.close(); } } }; const chrono::milliseconds timer_duration(static_cast<int>(1.0 / 60.0 * 1000)); void on_timer(Game& game, asio::steady_timer& timer) { game.update(); game.draw(); timer.expires_from_now(timer_duration); timer.async_wait( boost::bind(&on_timer, boost::ref(game), boost::ref(timer))); } int main() { Game game; asio::io_service io_service; asio::steady_timer timer(io_service); timer.expires_from_now(timer_duration); timer.async_wait( boost::bind(&on_timer, boost::ref(game), boost::ref(timer))); io_service.run(); }