5

新しい Boost 1.44.0 MSM ライブラリを使用してステート マシンを作成しています。このステート マシンには、 と の 2 つのクラスのイベントがclass1ありclass2ます。class1イベントは状態によって処理されるかS1S2イベントclass2は状態によってのみ処理されますS2

特別なclass1イベントにより、状態から状態へupgrade_reqのアップグレードが要求されます。S1S2

Boost::MSM で次のように実装しました。

// State S1 and S2 allow any class1 events
struct class1 {};
// Only state S2 allows class2 events
struct class2 {};

// an upgrade request is a class1 event that requests an upgrade to state 2
struct upgrade_req : public class1 {};

struct MyFSM : public msm::front::state_machine_def< MyFSM >
{
    /// State 1. Allows any class1 event
    struct S1 : public msm::front::state<>
    {
        /// functor says "processing event in State 1"
        struct ProcessEvent { /* ... */ };

        struct internal_transition_table : mpl::vector<
            //        Event   Action        Guard
            //       +-------+-------------+------------+
            Internal< class1, ProcessEvent, none >
        > {};
    }; // S1

    /// State 2. Allows any class1 or class2 events
    struct S2 : public msm::front::state<>
    {
        /// functor says "processing event in State 2"
        struct ProcessEvent { /* ... */ };

        struct internal_transition_table : mpl::vector<
            //        Event   Action        Guard
            //       +-------+-------------+------------+
            Internal< class1, ProcessEvent, none >,
            Internal< class2, ProcessEvent, none >
        > {};
    }; // S2

    /// everybody starts in state 1
    typedef S1 initial_state;

    /// send an error if a class2 event was received for state1
    struct SendError { /* ... */ };

    /// Send a response to the upgrade request
    struct SendUpgradeRsp { /* ... */ };

    /// functor returns true if the request to upgrade to state 2 is OK.
    struct VerifyUpgradeReq { /* ... */ };

    struct transition_table : mpl::vector<
        //  Start  Event         Next   Action           Guard
        // +------+-------------+------+----------------+------------------+
        Row< S1,   class1,       none,  none,            none,
        Row< S1,   class2,       S1,    SendError,       none >,
        Row< S1,   upgrade_req,  S2,    SendUpgradRsp,   VerifyUpgradeReq >,

        Row< S2,   class1,       none,  none,            none,
        Row< S2,   class2,       none,  none,            none >
    > {};
}; // MyFSM

私の問題は、これをそのまま使用すると、upgrade_reqイベントが main によって処理されないことですMyFSM::transition_table。によってのみ処理されますS1::internal_transition_table

例えば:

int main( int argc, char* argv[] )
{
    msm::back::state_machine< MyFSM > sm;
    sm.start();
    sm.process_event( class1() );
    sm.process_event( upgrade_req() ); 
    sm.process_event( class2() );
    return 0;
}

これの出力を次のようにしたいと思います。

状態 1 の処理イベント。
アップグレード要求 OK。
状態 2 の処理イベント。

しかし、私が得るのはこれです:

状態 1 の
イベントを処理しています。状態 1 のイベントを処理しています。
エラー。状態 1 でクラス 2 イベントを受け取りました。

この問題を解決する方法について誰か提案がありますか?

ありがとう、ポールH

4

1 に答える 1

5

問題は、内部遷移の優先度が遷移表で定義されているものよりも高いことです。そして、update_reqがclass1であるため、内部トランジットが起動します。これは実際にはUML標準に準拠しています。MSMは2番目のソリューションを提供します。internal_transition_tableを使用する代わりに、transition_table内のターゲットとして何もない行を使用してS1の内部遷移を定義できます。遷移S1+upgrade_reg-> S2の前に定義すると、優先度が低くなり、もう一方が考慮できない場合にのみ試行されます。

internal_transition_tableがどうしても必要な場合は、update_reqでない場合にのみ、class1を拒否するためのガードを提供できます。

HTH、クリストフヘンリー

PS:私は運が良かっただけでこの投稿を見つけました。ブーストユーザーリストに投稿すると、はるかに迅速な回答が保証されます。

于 2010-11-02T22:27:37.280 に答える