読者です 読者をやめる 読者になる 読者になる

Boost.Contextの動作確認

C++

Boost.Contextを動かす環境ができたので、どういうことをしたらどういう動きになるのか確認してみます。
ここで使用しているcontinuationクラスは、Boost.Contextのサンプルとして用意されてる、継続のための簡単なラッパーです。

#include <iostream>
#include <boost/context/all.hpp>
#include <boost/function.hpp>

class continuation {
    boost::contexts::context ctx_;
    boost::function<void(continuation&)> fn_;
    bool started_;

    void trampoline_()
    { fn_(*this); }

public:
    continuation(boost::function<void(continuation&)> const& fn) :
        ctx_(
            &continuation::trampoline_, this,
            boost::contexts::default_stacksize(),
            boost::contexts::no_stack_unwind, boost::contexts::return_to_caller),
        fn_(fn), started_(false)
    {}

    void resume()
    {
        if (!started_) {
            started_ = true;
            ctx_.start();
        }
        else {
            ctx_.resume();
        }
    }

    void suspend()
    { ctx_.suspend(); }

    bool is_complete() const
    { return ctx_.is_complete(); }
};

void f(continuation& cont)
{
    for (int i = 0; i < 5; ++i) {
        std::cout << i << std::endl;
        cont.suspend();
    }
}

int main()
{
    continuation cont(f);

    cont.resume(); // 0が出力される
    cont.resume(); // 1が出力される
    cont.resume(); // 2が出力される
    cont.resume(); // 3が出力される
    cont.resume(); // 4が出力される
    cont.resume(); // 終了。何も出力されない。

    std::cout << std::boolalpha << cont.is_complete() << std::endl;

    // さらに呼んでみる
    cont.resume(); // assert!
}
0
1
2
3
4
true
Assertion failed: ! is_complete(), file c:\library\boost\trunk\boost-svn\boost\c
ontext\detail\context_base.hpp, line 160

contextとして登録された関数の中でsuspend()関数を呼ぶと、そのコンテキストを一旦抜けて呼び出し元のコンテキストに移動します。
コンテキストを実行する側でresume()関数を呼ぶと、前回suspend()が呼ばれた後からsuspend()関数が呼ばれるまでを実行します。
for文の最後でsuspend()してるので、resume()は一回余計に呼べますが、呼んでもfor文の最後から関数を抜けるまでを実行するだけなので、何も出力されません。
is_complete()関数で、コンテキストの実行が完了してるかどうかを判定することができます。is_complete() == trueの状態でさらにresume()を呼ぼうとすると、resume()関数内でassertに引っかかります。


なので、resume()する側のコードは以下のようにしておくとよさそうです。

continuation cont(f);

while (!cont.is_complete()) {
    cont.resume();
}