【问题标题】:Deferring events from sub state machine延迟来自子状态机的事件
【发布时间】:2018-12-21 14:33:04
【问题描述】:

在我的项目中,有一个使用 boost 元状态机实现的状态机。这个主状态机,有一个状态(为了简单起见,我们称之为SubMachineEntry),它代表一个子状态机的入口点:

namespace msmf = boost::msm::front;
namespace msmb = boost::msm::back;
...
msmf::Row < SomeState, enterSub, SubMachineEntry, msmf::none, msmf::none >
...
using SubMachine = msmb::state_machine<SubMachine_>;

这个子状态机执行一些处理,然后我们回到外部状态机,去状态

using SubMachineFinished = SubMachine::exit_pt<...>;

,代表子机的退出状态。我的问题是,在子状态机退出之前,可能会调度某个事件(toProcessInOuter),应该在子状态机退出后在外部状态机中处理。将该事件在子状态机中的所有状态中延迟是行不通的,它不会传播到SubMachineFinished 之后的状态。有没有办法使用 boost MSM 的某种机制来实现这种事件的转发,而不使用一些自定义的解决方法?

【问题讨论】:

    标签: c++ boost state-machine boost-msm


    【解决方案1】:

    不幸的是,子机上的延迟事件无法在 MSM 上的父状态机上进行评估。所以你需要在父状态下编写延迟转换。

    从内部状态机到外部状态机评估事件。如果要延迟事件,可以在父状态中编写延迟转换。 我编写了演示它的示例。

    见附图。假设Event2 是您要推迟的事件。您需要将延迟转换写入State1

    这是整个代码:

    #include <iostream>
    #include <boost/msm/back/state_machine.hpp>
    
    #include <boost/msm/front/state_machine_def.hpp>
    #include <boost/msm/front/functor_row.hpp>
    
    namespace msm = boost::msm;
    namespace msmf = boost::msm::front;
    namespace mpl = boost::mpl;
    
    // ----- Events
    struct Event1 {};
    struct Event2 {};
    
    // ----- State machine
    struct OuterSm_:msmf::state_machine_def<OuterSm_> {
        struct State1_:msmf::state_machine_def<State1_> {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) const {
                std::cout << "State1::on_entry()" << std::endl;
            }
            template <class Event,class Fsm>
            void on_exit(Event const&, Fsm&) const {
                std::cout << "State1::on_exit()" << std::endl;
            }
    
            struct SubState1:msmf::state<> {
                template <class Event,class Fsm>
                void on_entry(Event const&, Fsm&) const {
                    std::cout << "SubState1::on_entry()" << std::endl;
                }
                template <class Event,class Fsm>
                void on_exit(Event const&, Fsm&) const {
                    std::cout << "SubState1::on_exit()" << std::endl;
                }
            };
            template <class Fsm,class Event> 
            void no_transition(Event const& e, Fsm& ,int state) {
                std::cout << "No handled event in InnerSm " << typeid(e).name() << " on State " << state << std::endl;
            }
            struct Exit1:msmf::exit_pseudo_state<msmf::none> {};
            // Set initial state
            typedef mpl::vector<SubState1> initial_state;
            // Transition table
            struct transition_table:mpl::vector<
                //          Start      Event   Next        Action       Guard
                msmf::Row < SubState1, Event1, Exit1,      msmf::none,  msmf::none >
                > {};
        };
        struct State2:msmf::state<> {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) const {
                std::cout << "State2::on_entry()" << std::endl;
            }
            template <class Event,class Fsm>
            void on_exit(Event const&, Fsm&) const {
                std::cout << "State2::on_exit()" << std::endl;
            }
        };
        template <class Fsm,class Event> 
        void no_transition(Event const& e, Fsm& ,int state) {
            std::cout << "No handled event in OuterSm " << typeid(e).name() << " on State " << state << std::endl;
        }
    
        typedef msm::back::state_machine<State1_> State1;
        // Actions
        struct Action {
            template <class Event, class Fsm, class SourceState, class TargetState>
            void operator()(Event const&, Fsm&, SourceState&, TargetState&) const {
                std::cout << "Action()" << std::endl;
            }
        };
        // enable deferred events
        typedef int activate_deferred_events;
        // Set initial state
        typedef State1 initial_state;
        // Transition table
        struct transition_table:mpl::vector<
            //          Start             Event       Next        Action       Guard
            msmf::Row < State1::exit_pt
                        <State1_::Exit1>, msmf::none, State2,     msmf::none,  msmf::none >,
            msmf::Row < State1,           Event2,     msmf::none, msmf::Defer, msmf::none >,
            msmf::Row < State2,           Event2,     msmf::none, Action,      msmf::none >
        > {};
    };
    
    // Pick a back-end
    typedef msm::back::state_machine<OuterSm_> Osm;
    
    
    int main() {
        Osm osm;
        osm.start(); 
    
        std::cout << "> Send Event2()" << std::endl;
        osm.process_event(Event2());
        std::cout << "> Send Event1()" << std::endl;
        osm.process_event(Event1());
        return 0;
    }
    

    运行演示:https://wandbox.org/permlink/WQixcoGGQwAWou34

    【讨论】:

    • 你好高俊!抱歉回复晚了!我更容易推迟外部机器中的事件。但是,我只知道声明using deferred_events = mpl::vector&lt;...&gt; 的方法,但我不知道如何处理子状态机的退出状态。我不知道有特殊的Defer 操作。无论如何,它工作得很好。非常感谢您的详细解答!我会将答案标记为已接受!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 2021-11-06
    相关资源
    最近更新 更多