我来自 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} );
}
};
为了访问状态机本身,您需要将应用程序类分为基类和子类。 基类具有纯虚成员函数声明。 您可以从 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
}
可运行演示: