I am attempting to use Boost State Machine, but I have encountered a Segmentation Fault when running my machine in an infinite loop. Essentially I have the same example in the boost state machine functor example shown below:
The only difference is that I now trigger "event1" to occur as soon as I enter State4, hence creating a loop. This works for several thousand iterations but then it will seg fault. Am I breaking some kind of UML rule and overflowing the stack? I basically only have one blocking event and then I want all the other states to trigger automatically, and then end up in State4 (which in reality would be a blocking call waiting for a message from the network for example). How would I properly implement this using Meta State Machine so I don't blow up the stack?
UPDATE
I've included a the source code that is causing my problems here:
http://pastebin.com/fu6rzF0Q
This is basically the example in functor front end except with the following changes:
Added "pretend" blocking call function:
struct BlockingCall {
template <class EVT, class FSM, class SourceState, class TargetState>
void operator()(EVT const &, FSM &, SourceState &, TargetState &) {
std::cout << "my_machine::Waiting for a thing to happen..." << std::endl;
// Pretend I'm actually waiting for something
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "my_machine::OMG the the thing happened!" << std::endl;
}
};
And I also updated the last line in the transition table:
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
Row < State1 , none , State2 >,
Row < State2 , none , State3 , State2ToState3 >,
Row < State3 , none , State4 , none , always_false >,
// +---------+-------------+---------+---------------------+----------------------+
Row < State3 , none , State4 , State3ToState4 , always_true >,
Row < State4 , none , State1 , BlockingCall >
// +---------+-------------+---------+---------------------+----------------------+
> {};
Notice that there is no longer an event that needs to triggered to move from State4 to State1. This code with out a doubt give you a seg fault and will have a stack trace that is 1000s of lines long.
I should also note that regardless of the time I wait, I always eventually seg fault. I've played around with changing the sleep to 1 - 100 and it will eventually die. I guess I need some way of unrolling the stack once a single loop has completed.
UPDATE 2 So I found that I don't seg fault when I trigger on the event in an infinite loop. Here is what I did:
First I set the transition table back to the original example:
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
Row < State1 , none , State2 >,
Row < State2 , none , State3 , State2ToState3 >,
Row < State3 , none , State4 , none , always_false >,
// +---------+-------------+---------+---------------------+----------------------+
Row < State3 , none , State4 , State3ToState4 , always_true >,
Row < State4 , event1 , State1 , none >
// +---------+-------------+---------+---------------------+----------------------+
> {};
Then I changed the main program to the following:
void test() {
my_machine p;
// needed to start the highest-level SM. This will call on_entry and mark the
// start of the SM
// in this case it will also immediately trigger all anonymous transitions
p.start();
// this event will bring us back to the initial state and thus, a new "loop"
// will be started
while (true) {
p.process_event(event1());
}
}
And now I have been running at full speed (no sleeps) and I haven't seg faulted. Based on this, it seems there is no way to start a state machine and just have it run and process internal events, is that correct? I always have to have some process on the outside that triggers at least on even?
UPDATE 3
Ultimately my goal is to implement something like the following picture:
My intent is to have the state machine started, and then it will simply wait for incoming messages without any further intervention.