【问题标题】:[Boost::ext].SML: Is there a way to store a callback to later process an event?[Boost::ext].SML:有没有办法存储回调以便稍后处理事件?
【发布时间】:2020-10-16 10:17:29
【问题描述】:

我来自 Boost MSM,现在我正在尝试使用 SML 1.1.3 实现相同的状态机。 使用 SML,我无法访问状态机本身,我不得不使用注入的依赖项。我也大量使用 D-Bus,现在我在进行异步 D-Bus 调用时遇到了问题。异步 D-Bus 调用是在注入依赖项的方法中进行的。当 D-Bus 调用完成时,将调用依赖项内的回调。我需要一种向状态机发出事件的方法。 存储 sml::back::process 不起作用,我无法确定在异步 D-Bus 调用完成时它是否仍然有效。

例子:

    auto queryDBusAction = []( Dep& dep, sml::back::process<Ev_Result> processEvent ) {
        dep.makeAsyncDBusCall( SomeCallback );
    };

...

class Dep
{
public:
    void makeAsyncDBusCall( SomeCallback cb )
    {
        _cb = cb;
        _client.someAsyncDBusCall( boost::bind( &Dep::dbusCallFinished, this, _1 ) );
    }

protected:
    DBusClient _client;
    SomeCallback _cb;

    void dbusCallFinished( Result& result, const DBus::Error& dbusError )
    {
        // Here I need a way/callback to emit an event
        // that gets processed by the state machine
        _cb( Ev_Result{result} );
    }
};

【问题讨论】:

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


    【解决方案1】:

    为了访问状态机本身,您需要将应用程序类分离为基类和子类。 基类有纯虚成员函数声明。 您可以从 sml 转换表操作中调用成员函数。

    您需要在定义转换表之后定义子类。 现在,子类可以访问转换表的整个定义。 这意味着您可以将sml::sm 包含为子类的成员

    所以你可以从成员函数中调用 sml 后端的process_event() 函数。见memfun1()

    #include <iostream>
    #include <cassert>
    
    #include <boost/sml.hpp>
    #include <boost/asio.hpp>
    
    namespace sml = boost::sml;
    
    struct e1 {};
    struct e2 {};
    
    // Separate member function declarations as the base class
    struct app_base {
        virtual void memfun1() = 0;
        virtual void memfun2(int) const = 0;
        virtual ~app_base() = default;
    };
        
    struct app_table {
        auto operator()() const noexcept {
            using namespace sml;
            // I can write member function call in action thanks to base class app_base
            return make_transition_table(
                // source event      guard                     action                                    target
                *"s1"_s + event<e1>  [([] { return true; })] / [](app_base& appb)  { appb.memfun1(); }   = "s2"_s
                ,"s2"_s + event<e2>                          / [](app_base& appb)  { appb.memfun2(42); } = "s1"_s
            );
        }
    };
    
    struct app : app_base {
        app(boost::asio::io_context& ioc):ioc { ioc } {}
        
        // post asynchronous callback function that calls process_event()
        void memfun1() override {
            std::cout << __PRETTY_FUNCTION__ << std::endl;
            boost::asio::post(
                ioc, 
                [this] { 
                    std::cout << "async callback is called. call process_event()" << std::endl;
                    sm_.process_event(e2{});
    
                    using namespace sml;
                    assert(sm_.is("s1"_s));
                }
            );
        }
        void memfun2(int v) const override {
            std::cout << __PRETTY_FUNCTION__ << ":" << v << std::endl;
        }
    
        // state machine backend can be a member of application class
        sml::sm<app_table> sm_ { static_cast<app_base&>(*this) };
        boost::asio::io_context& ioc;
    };
    
    int main() {
        using namespace sml;
        boost::asio::io_context ioc; // for async operation example
        
        app a { ioc };
        assert(a.sm_.is("s1"_s));
        a.sm_.process_event(e1{});
        assert(a.sm_.is("s2"_s));
        
        ioc.run(); // async loop start until async event will become empty
    }
    

    可运行演示:https://wandbox.org/permlink/9XFQAMHuRcMPeU64

    【讨论】:

    • 我将所有其他 SM 的通用代码(不同的程序,但通用代码)移动到单独的类/依赖项(如 app_base)中,并且类 app 也继承自它。我现在的问题是,这个类也需要发送事件。如果我将 SM 定义移动到此类(受保护的成员)中,那么我需要将其作为模板,并将 SM 类型作为参数。但是我必须将该模板的一个实例注入到 SM 中,并且需要为每种 SM 类型复制常见的操作和守卫,还是我看错了?
    • 嗯……我只理解文字表达太复杂了。关键是定义顺序。 1.需要从表中的SML动作调用的类定义和成员函数声明。 2.定义表。 3.定义1的派生类。我不确定,但你可以使用app_base和app作为公共基础。并且每个类都可以派生自类app。
    猜你喜欢
    • 2012-08-24
    • 2016-05-09
    • 2020-05-04
    • 1970-01-01
    • 2013-05-10
    • 1970-01-01
    • 2023-03-04
    • 2010-09-25
    • 1970-01-01
    相关资源
    最近更新 更多