最終更新日時:
が更新

履歴 編集

有限状態マシン

有限状態マシン(finite state machine)を扱うライブラリとしてBoost.StatechartとBoost.MSM (Meta State Machine)のふたつが存在する。

ここではBoost.MSMの利用方法を紹介する。

インデックス

有限状態マシンの定義と利用

有限状態マシンを利用するために、状態・イベント・有限状態マシンをそれぞれ定義する必要がある。

状態遷移は有限状態マシンの中にテーブル状にして記述する。

#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/back/state_machine.hpp>

using namespace boost::msm::front;

// 状態の定義
struct my_state1 : state<> {};
struct my_state2 : state<> {};
struct my_state3 : state<> {};

// イベントの定義
struct my_event1 {};
struct my_event2 {};

// 有限状態マシンの定義
struct my_machine_ : state_machine_def< my_machine_ >
{
    // 状態遷移テーブル
    struct transition_table : boost::mpl::vector
        //       source  |   event  |  target
        < _row< my_state1, my_event1, my_state2 >
        , _row< my_state2, my_event1, my_state1 >
        , _row< my_state2, my_event2, my_state3 >
        > {};

    // 初期状態
    typedef my_state1 initial_state;
};

typedef boost::msm::back::state_machine< my_machine_ > my_machine;

int main()
{
    my_machine m;
    m.start();                       // my_state1
    m.process_event( my_event1() );  // my_state1 -> my_state2
    m.process_event( my_event2() );  // my_state2 -> my_state3
}

状態の開始と終了のタイミングで任意の処理を行う

状態クラスに on_entry(), on_exit() メンバ関数を定義すると、それぞれ状態の開始と終了時に、自動的に呼ばれる。

#include <iostream>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/back/state_machine.hpp>

using namespace boost::msm::front;

struct my_state1 : state<>
{
    // my_state1 状態が終わるときに呼ばれる。
    template < class event_t, class fsm_t >
    void on_exit( event_t const & e, fsm_t & machine )
    {
       std::cout << "exit: my_state1" << std::endl;
    }
}; 

struct my_state2 : state<>
{
    // my_state2 状態が始まるときに呼ばれる。
    template < class event_t, class fsm_t >
    void on_entry( event_t const & e, fsm_t & machine )
    {
        std::cout << "entry: my_state2" << std::endl;
    }
};

struct my_event1 {};

struct my_machine_ : state_machine_def< my_machine_ >
{
    struct transition_table : boost::mpl::vector
    < _row< my_state1, my_event1, my_state2 > > {};

    typedef my_state1 initial_state; 
};


typedef boost::msm::back::state_machine< my_machine_ > my_machine; 


int main()
{
    my_machine m; 
    m.start();                      // my_state1 
    m.process_event( my_event1() ); // my_state1 -> my_state2 
}

実行結果:

exit: my_state1
entry: my_state2

状態遷移イベントを受け取ったタイミングで任意の処理を行う

有限状態マシンがイベントを受け取ったとき、任意の処理を実行できる。

状態遷移テーブルには _row のかわりに a_row を使う。

#include <iostream>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/back/state_machine.hpp>

using namespace boost::msm::front;

struct my_state1 : state<> {};
struct my_state2 : state<> {};
struct my_state3 : state<> {};

struct my_event1 {};
struct my_event2 {};

struct my_machine_ : state_machine_def< my_machine_ >
{
    void on_event1( my_event1 const & ev ) { std::cout << "on_event1" << std::endl; }
    void on_event2( my_event2 const & ev ) { std::cout << "on_event2" << std::endl; }

    // 状態遷移テーブル 
    struct transition_table : boost::mpl::vector 
        // source | event | target | action 
        < a_row< my_state1, my_event1, my_state2, &my_machine_::on_event1 > 
        ,  _row< my_state2, my_event1, my_state1                          > 
        , a_row< my_state2, my_event2, my_state3, &my_machine_::on_event2 > 
        > {}; 

    typedef my_state1 initial_state; 
}; 


typedef boost::msm::back::state_machine< my_machine_ > my_machine; 


int main() 
{ 
    my_machine m; 

    m.start();                      // my_state1 
    m.process_event( my_event1() ); // my_state1 -> my_state2 ( on_event1 ) 
    m.process_event( my_event2() ); // my_state2 -> my_state3 ( on_event2 ) 
}

実行結果:

on_event1
on_event2

状態遷移を拒否する

有限状態マシンがイベントを受け取ったとき、実行時に状態遷移を拒否することができる。

状態遷移テーブルには _row の代わりに g_row を使う。

g_row に指定したメンバ関数が false を返すとき、状態遷移は拒否される。

#include <iostream>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/back/state_machine.hpp>

using namespace boost::msm::front;

// 状態の定義
struct my_state1 : state<> {};
struct my_state2 : state<>
{
    template < class event_t, class fsm_t >
    void on_entry( event_t const & e, fsm_t & machine )
    {
        std::cout << "entry: my_state2" << std::endl;
    }
};
struct my_state3 : state<>
{
    template < class event_t, class fsm_t >
    void on_entry( event_t const & e, fsm_t & machine )
    {
        std::cout << "entry: my_state3" << std::endl;
    }
};

struct my_event1 {};
struct my_event2 {};

struct my_machine_ : state_machine_def< my_machine_ >
{
    bool guard_1( my_event1 const & ev ) { return true; }
    bool guard_2( my_event2 const & ev ) { return false; }

    // 状態遷移テーブル
    struct transition_table : boost::mpl::vector
        // source | event | target | guard
        < g_row< my_state1, my_event1, my_state2, &my_machine_::guard_1 >
        ,  _row< my_state2, my_event1, my_state1                        >
        , g_row< my_state2, my_event2, my_state3, &my_machine_::guard_2 >
        > {};

    typedef my_state1 initial_state;
};

typedef boost::msm::back::state_machine< my_machine_ > my_machine;

int main()
{
    my_machine m;

    m.start();                      // my_state1
    m.process_event( my_event1() ); // my_state1 -> my_state2
    m.process_event( my_event2() ); // 拒否。
}

実行結果:

entry: my_state2