gpt4 book ai didi

c++ - 使用信号处理程序触发事件时,如何让 boost.msm 正确更改状态?

转载 作者:行者123 更新时间:2023-11-28 05:41:07 25 4
gpt4 key购买 nike

我的 (boost.msm) 状态机在使用信号处理程序时出现“回滚”触发事件。但是,当我使用直接调用来触发事件时,状态机器运行正常。

我查看了 boost 文档并搜索了网络,但似乎所有示例都使用直接调用来触发事件。我也搜索过,但找不到任何解决此主题的内容。

我正在学习 boost 元状态机库,看看是否替换现有的“本土”状态机库会很有用目前由我的开发团队使用。

为了让它工作,我需要能够触发状态机事件来自信号处理程序(处理来自 boost.signals2 的信号)。

我创建了一个简单但人为设计的示例来对其进行测试运行,并且当我看到第一个事件被触发后,状态时感到困惑机器正确地(但暂时地)改变了状态(在信号处理程序中)但显然在返回主界面后“回滚”。

当我绕过信号处理程序时(通过直接调用 process_event)一切正常。

无可否认,测试状态机旨在执行此操作:

[state_a]--event_a-->[state_b]--event_b-->[state_c]--event_c-->{back-to-state_a}

我想知道如何让这个设计(或类似的东西)发挥作用使用信号处理程序正确触发状态机事件。使用直接电话对我来说不是一个选择,因为我只接收信号来工作。

我在下面包含了测试代码。注意主要的前半部分函数执行信号处理程序触发和 main 的后半部分练习直接调用触发(使用 g++ main.cpp -omain' 或 'clang++ main.cpp -omain 编译):

#include <iostream>
#include <boost/signals2.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/back/tools.hpp>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>

typedef boost::signals2::signal<void()> sig1_t;

//================================================================================
// ------- Sensors section

struct sensor_a {
sig1_t& get_sig() { return sig; }
void emit() { sig(); }

private:
sig1_t sig;
};

struct sensor_b {
sig1_t& get_sig() { return sig; }
void emit() { sig(); }

private:
sig1_t sig;
};

struct sensor_c {
sig1_t& get_sig() { return sig; }
void emit() { sig(); }

private:
sig1_t sig;
};

//========================================
// Sensors class
struct Sensors {
sensor_a& get_sa() {
return sa;
}

sensor_b& get_sb() {
return sb;
}

sensor_c& get_sc() {
return sc;
}

private:
sensor_a sa;
sensor_b sb;
sensor_c sc;
};

// ----- Events
struct event_a {
std::string name() const { return "event_a"; }
};
struct event_b {
std::string name() const { return "event_b"; }
};
struct event_c {
std::string name() const { return "event_c"; }
};
struct exit {
std::string name() const { return "exit"; }
};

//================================================================================
// ----- State machine section

namespace msm = boost::msm;
namespace msmf = boost::msm::front;
namespace mpl = boost::mpl;

class Controller; // forward declaration

//========================================
// testmachine class (the state machine)
struct testmachine : msmf::state_machine_def<testmachine>
{
testmachine(Controller& c) : controller(c) {}

template <class Fsm,class Event>
void no_transition(Event const& e, Fsm& ,int state) {
std::cout << "testmachine::no_transition -- No transition for event: '"
<< e.name() << "'" << " on state: " << state << std::endl;
}

//---------
struct state_a : msmf::state<> {
template <class Event,class Fsm>
void on_entry(Event const&, Fsm&) const {
std::cout << "state_a::on_entry() " << std::endl;
}

template <class Event,class Fsm>
void on_exit(Event const&, Fsm&) const {
std::cout << "state_a::on_exit()" << std::endl;
}
};

//---------
struct state_b : msmf::state<> {
template <class Event,class Fsm>
void on_entry(Event const& e, Fsm&) const {
std::cout << "state_b::on_entry() -- event: " << e.name() << std::endl;
}

template <class Event,class Fsm>
void on_exit(Event const& e, Fsm&) const {
std::cout << "state_b::on_exit() -- event: " << e.name() << std::endl;
}
};

//---------
struct state_c : msmf::state<> {
template <class Event,class Fsm>
void on_entry(Event const& e, Fsm&) const {
std::cout << "state_c::on_entry() -- event: " << e.name() << std::endl;
}

template <class Event,class Fsm>
void on_exit(Event const& e, Fsm&) const {
std::cout << "state_c::on_exit() -- event: " << e.name() << std::endl;
}
};

//---------
// Set initial state
typedef mpl::vector<state_a> initial_state;

//---------
// Transition table
struct transition_table:mpl::vector<
// Start Event Next Action Guard
msmf::Row < state_a, event_a, state_b, msmf::none, msmf::none >,
msmf::Row < state_b, event_b, state_c, msmf::none, msmf::none >,
msmf::Row < state_c, event_c, state_a, msmf::none, msmf::none >
> {};

private:
Controller& controller;
};

// state-machine back-end
typedef msm::back::state_machine<testmachine> TestMachine;

//================================================================================
// --------- controller section

namespace msm = boost::msm;
namespace mpl = boost::mpl;

// debug print helper:
std::string demangle(const std::string& mangled) {
int status;
char* c_name = abi::__cxa_demangle(mangled.c_str(), 0, 0, &status);

if(c_name){
std::string retval(c_name);
free((void*)c_name);
return retval;
}

return mangled;
}

// debug print helper (from boost msm documentation):
void pstate(TestMachine const& sm) {
typedef TestMachine::stt Stt;
typedef msm::back::generate_state_set<Stt>::type all_states;
static char const* state_names[mpl::size<all_states>::value];
mpl::for_each<all_states,boost::msm::wrap<mpl::placeholders::_1> >
(msm::back::fill_state_names<Stt>(state_names));

for (unsigned int i=0;i<TestMachine::nr_regions::value;++i){
std::cout << " -> " << demangle(state_names[sm.current_state()[i]])
<< std::endl;
}
}

//========================================
// Controller class
struct Controller {
Controller(Sensors& s) :
sensors(s),
tm(boost::ref(*this)) {
s.get_sa().get_sig().connect(boost::bind(&Controller::on_sa_event, *this));
s.get_sb().get_sig().connect(boost::bind(&Controller::on_sb_event, *this));
s.get_sc().get_sig().connect(boost::bind(&Controller::on_sc_event, *this));
tm.start();
}

void on_sa_event() {
std::cout << "Controller::on_sa_event function entered ++++++++" << std::endl;
current_state(__FUNCTION__);
trigger_event_a();
current_state(__FUNCTION__);
std::cout << "Controller::on_sa_event function exiting --------" << std::endl;
};

void on_sb_event() {
std::cout << "Controller::on_sb_event function entered ++++++++" << std::endl;
current_state(__FUNCTION__);
trigger_event_b();
current_state(__FUNCTION__);
std::cout << "Controller::on_sb_event function exiting --------" << std::endl;
};

void on_sc_event() {
std::cout << "Controller::on_sc_event function entered ++++++++" << std::endl;
current_state(__FUNCTION__);
trigger_event_c();
current_state(__FUNCTION__);
std::cout << "Controller::on_sc_event function exiting --------" << std::endl;
};

// debug print function
void current_state(const std::string& f) {
std::cout << "\nController::current_state ("
<< "called from function: " << f
<<")" << std::endl;
pstate(tm);
std::cout << std::endl;
}

void trigger_event_a() {
std::cout << "Controller::trigger_event_a" << std::endl;
tm.process_event(event_a());
current_state(__FUNCTION__);
}

void trigger_event_b() {
std::cout << "Controller::trigger_event_b" << std::endl;
tm.process_event(event_b());
current_state(__FUNCTION__);
}

void trigger_event_c() {
std::cout << "Controller::trigger_event_c" << std::endl;
tm.process_event(event_c());
current_state(__FUNCTION__);
}

private:
Sensors& sensors;
TestMachine tm;
};

//================================================================================
// --------- main
int main() {
Sensors sensors;
Controller controller(sensors);

std::cout << "Exercise state machine using signal handlers (fails):" << std::endl;
controller.current_state("***** main");
sensors.get_sa().emit();

controller.current_state("***** main");
sensors.get_sb().emit();

controller.current_state("***** main");
sensors.get_sc().emit();

controller.current_state("***** main");

std::cout << "\nExercise state machine using direct calls (works):" << std::endl;
controller.current_state("***** main");
controller.trigger_event_a();

controller.current_state("***** main");
controller.trigger_event_b();

controller.current_state("***** main");
controller.trigger_event_c();

controller.current_state("***** main");
}

这是输出:

 1  state_a::on_entry()
2 Exercise state machine using signal handlers (fails):

3 Controller::current_state (called from function: ***** main)
4 -> testmachine::state_a

5 Controller::on_sa_event function entered ++++++++

6 Controller::current_state (called from function: on_sa_event)
7 -> testmachine::state_a

8 Controller::trigger_event_a
9 state_a::on_exit()
10 state_b::on_entry() -- event: event_a

11 Controller::current_state (called from function: trigger_event_a)
12 -> testmachine::state_b

13 Controller::current_state (called from function: on_sa_event)
14 -> testmachine::state_b

15 Controller::on_sa_event function exiting --------

16 Controller::current_state (called from function: ***** main)
17 -> testmachine::state_a

18 Controller::on_sb_event function entered ++++++++

19 Controller::current_state (called from function: on_sb_event)
20 -> testmachine::state_a

21 Controller::trigger_event_b
22 testmachine::no_transition -- No transition for event: 'event_b' on state: 0

23 Controller::current_state (called from function: trigger_event_b)
24 -> testmachine::state_a

25 Controller::current_state (called from function: on_sb_event)
26 -> testmachine::state_a

27 Controller::on_sb_event function exiting --------

28 Controller::current_state (called from function: ***** main)
29 -> testmachine::state_a

30 Controller::on_sc_event function entered ++++++++

31 Controller::current_state (called from function: on_sc_event)
32 -> testmachine::state_a

33 Controller::trigger_event_c
34 testmachine::no_transition -- No transition for event: 'event_c' on state: 0

35 Controller::current_state (called from function: trigger_event_c)
36 -> testmachine::state_a

37 Controller::current_state (called from function: on_sc_event)
38 -> testmachine::state_a

39 Controller::on_sc_event function exiting --------

40 Controller::current_state (called from function: ***** main)
41 -> testmachine::state_a

42 Exercise state machine using direct calls (works):

43 Controller::current_state (called from function: ***** main)
44 -> testmachine::state_a

45 Controller::trigger_event_a
46 state_a::on_exit()
47 state_b::on_entry() -- event: event_a

48 Controller::current_state (called from function: trigger_event_a)
49 -> testmachine::state_b

50 Controller::current_state (called from function: ***** main)
51 -> testmachine::state_b

52 Controller::trigger_event_b
53 state_b::on_exit() -- event: event_b
54 state_c::on_entry() -- event: event_b

55 Controller::current_state (called from function: trigger_event_b)
56 -> testmachine::state_c

57 Controller::current_state (called from function: ***** main)
58 -> testmachine::state_c

59 Controller::trigger_event_c
60 state_c::on_exit() -- event: event_c
61 state_a::on_entry()

62 Controller::current_state (called from function: trigger_event_c)
63 -> testmachine::state_a

64 Controller::current_state (called from function: ***** main)
65 -> testmachine::state_a

为了便于引用,我通过后处理输出文件添加了行号。

输出的第 01 行显示状态机正确地从state_a 的初始伪状态。

输出的第 14 行显示状态机正确地从在 on_sa_event 函数内部时,state_a 到 state_b。

但是,第 17 行显示状态机在从测试时返回到 state_a主要(!)

状态机在 state_a 中保持剩余的转换信号处理程序测试(第 18-41 行),导致一些“无转换”错误消息。

对于直接调用练习(输出行 42-65),状态机转换正确地通过所有状态并且它的“当前状态”没有区别从触发函数内和在 main 中时(触发后函数调用)。

环境:操作系统:“Ubuntu 16.04 LTS”

g++版本:(Ubuntu 5.3.1-14ubuntu2)5.3.1 20160413

boost 版本:boost_1_60_0

最佳答案

问题是复制*this引起的。请参见以下代码。 boost::bind 复制 *this.每个复制的 *this 都处于初始状态 (state_a)。这就是您遇到回滚的原因。

s.get_sa().get_sig().connect(boost::bind(&Controller::on_sa_event, *this));
s.get_sb().get_sig().connect(boost::bind(&Controller::on_sb_event, *this));
s.get_sc().get_sig().connect(boost::bind(&Controller::on_sc_event, *this));

如果您按如下方式复制 this 指针,您的代码将按预期工作。

s.get_sa().get_sig().connect(boost::bind(&Controller::on_sa_event, this));
s.get_sb().get_sig().connect(boost::bind(&Controller::on_sb_event, this));
s.get_sc().get_sig().connect(boost::bind(&Controller::on_sc_event, this));

你也可以绑定(bind) *this 的引用,如下所示:

s.get_sa().get_sig().connect(boost::bind(&Controller::on_sa_event, boost::ref(*this)));
s.get_sb().get_sig().connect(boost::bind(&Controller::on_sb_event, boost::ref(*this)));
s.get_sc().get_sig().connect(boost::bind(&Controller::on_sc_event, boost::ref(*this)));

关于c++ - 使用信号处理程序触发事件时,如何让 boost.msm 正确更改状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37082716/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com