2016-05-06 4 views
0

Mein (boost.msm) Zustandsautomat scheint zu rollen, wenn die Signalhandler Ereignisse auslösen. Wenn ich jedoch direkte Aufrufe zum Auslösen von Ereignissen verwende, verhält sich der Computer korrekt.Wie bekomme ich boost.msm, um den Zustand korrekt zu ändern, wenn ein Signalhandler zum Auslösen von Ereignissen verwendet wird?

Ich schaute in der Boost-Dokumentation und suchte das Web, aber es scheint, dass alle Beispiele direkte Aufrufe für Ereignisauslösung verwenden. Ich suchte auch SO, , aber konnte nichts finden, das dieses Thema anspricht.

ich dabei bin die Boost-Meta-Zustandsmaschine Bibliothek des Lernens zu sehen, ob es nützlich wäre, die bestehenden „home grown“ Zustandsmaschine Bibliothek derzeit von meiner Entwicklungsteam zu ersetzen.

Damit dies funktioniert, muss ich in der Lage sein, Zustandsautomatenereignisse von Signalhandlern auszulösen (Signale von boost.signals2 handhabend).

habe ich eine einfache, aber gekünstelt, beispiels es einen Testlauf zu geben und war verwirrte, als ich sah, dass nach dem ersten Ereignis ausgelöst wurde, wird der Zustand Maschine korrekt (aber vorübergehend) Zustände geändert (während im Signal Handler) aber anscheinend "zurückgerollt" nach der Rückkehr zum Haupt.

Wenn ich die Signalhandler umging (durch direkte Aufrufe von process_event) hat alles richtig funktioniert.

Die zugegebenermaßen gekünstelt, Testzustandsmaschine ist so ausgelegt, dies zu tun:

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

Ich mag würde wissen, wie ich diesen Entwurf machen (oder so ähnlich) arbeitet Signal-Handler mit Zustandsmaschine auslösen Ereignisse korrekt. Die Verwendung direkter Anrufe ist für mich keine Option, da ich nur Signale zur Bearbeitung empfange.

Ich habe den Testcode unten eingefügt. Man beachte, dass die erste Hälfte der Haupt Funktion Triggern die Signalbehandlungsroutine Übungen und die zweite Hälfte des Haupt den direkten Aufruf ausübt auslösenden (kompilierte g++ main.cpp -omain' or 'clang++ main.cpp -omain verwenden):

#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"); 
} 

Hier ist der Ausgang:

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 

Ich fügte Zeilennummern hinzu, indem ich die Ausgabedatei für eine einfachere Referenz nachbearbeitete.

Zeile 01 der Ausgabe zeigt, dass die Zustandsmaschine korrekt von den anfänglichen Pseudo-Zustand in state_a überging.

Die Zeile 14 der Ausgabe zeigt, dass die Statusmaschine korrekt von state_a in state_b überging, wenn sie innerhalb der Funktion on_sa_event war.

Zeile 17 zeigt jedoch die Zustandsmaschine, die beim Test von main (!)

Der Zustandsautomat bleibt in state_a für die restlichen Übergänge der Signal-Handler-Tests (Zeilen 18-41), was zu einigen "No Transition" -Fehlermeldungen führt.

Für die direkte Anruf Übung (Ausgangsleitungen 42-65), der Zustandsmaschine korrekt durch alle Staaten und es wird in ihm keinen Unterschied gibt ‚aktuellen Zustand‘ von innerhalb der Auslösefunktion, und wenn im Haupt (nach dem Triggerung Funktionsaufruf).

Umwelt: OS: "Ubuntu 16.04 LTS"

g ++ Version: (Ubuntu 5.3.1-14ubuntu2) 5.3.1 20160413

Boost-Version: boost_1_60_0

Antwort

1

Das Problem wird verursacht durch Kopieren * dies. Siehe den folgenden Code. boost :: bind kopiert * das. Jeder kopiert * Dies ist der Anfangszustand (state_a). Deshalb haben Sie den Rollback erlebt.

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)); 

Wenn Sie das dieses Zeiger kopieren, wie folgt, Ihr Code funktioniert wie erwartet.

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)); 

Sie können auch den Bezug von * diese binden, wie folgt:

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))); 
+0

Thank you! Genau das habe ich gebraucht! – mikero

+0

Ich vermutete, dass es sich um ein Problem mit dem Oszilloskop gehandelt haben könnte, aber ich vermisste völlig, dass meine (falsche) Verwendung von boost :: bind ein temporäres war - zusammen mit seinem temporären Umfang! :) – mikero

Verwandte Themen