
Tim, thanks for your earlier replies. I've been off the list for a while and couldn't respond earlier. Tim Milward wrote:
2. Is is somehow possible to reuse state definitions as substates of different "higher-level" states?
In boost/libs/statechart/doc/tutorial.html#TransitionActions it says, "With Boost.Statechart, a transition action can be a member of any common outer context" and goes on to give some examples. If I've understood your question correctly then the answer is "Yes".
Actually, I'm inclined to say "No" considering the following (partially duplicated from your part later in the posting):
Top Remote Idle Executing Local Idle Executing
This I cannot do, right? Idle and Executing would ideally be the same, but as they are statically associated with their outer states (and vice versa) it doesn't look like it's possible.
OK, I've miss understood. Does this help? boost/libs/statechart/doc/tutorial.html#SubmachinesAndParametrizedStates
It describes how to use templates to implement submachines. In the above example you'd use Executing<Remote> and Executing<Local>.
I tried this originally, but it somehow grew the complexity beyond my control so I reverted to my previous solution. IIRC it was rather complex to keep the forward declarations and actual definitions in the correct order when the template parameter was a kind of State. I might take another stab at it later. [snip]
Top Remote RIdle RExecuting Local LIdle LExecuting
This is more similar to what I've got. There isn't really any other code duplication that having to define the e.g. RIdle, LIdle, RExecuting, LExecuting, as the state machine itself holds a reference to the domain object responsible for executing the actions. Within the different states I simply get this object using context<StateMachine> and delegate - so the state machine is in this case only used for discriminating the disallowed events according to the current state.
So what is it you want to reuse? Is it a common list of reactions, to which each of L & RExecuting add the reactions specific to Local and Remote?
I did want to reuse the inner states - but in the end I found it wasn't worth the work involved, so I allowed myself to do some code duplication instead (which is basically what I said above - sorry for not being very clear).
UML provides "Do Activities" that can be used for this purpose. The statechart docs suggest simulating this "with a separate thread that is started in the entry action and canceled (!) in the exit action of a particular state". I quite like that approach.
I considered executing the commands in a worker thread similar to that approach; when receiving a command the FSM would enter the ExecutingCommand state, kick off a new thread (or using a previously existing worker thread) to execute the command. The problem I ran into that I wanted the command-executing thread _itself_ being able to signal the completion of the command (and thus trigger exiting the ExecutingCommand state to the previous state). It should never be possible to exit the state unless the command has run to an end, e.g. by unconditionally joining the worker thread in the state's destructor.
I couldn't really find a clean, thread-safe way to implement this. Did you actually try to implement anything like this?
Not yet. Can the worker thread, after processing the command push a Finished event onto the queue. When the statemachine thread receives this event it exits the Executing state.
I tried modeling this with an asynchronous statemachine and it looks promising. There's just one thing that I don't like - it doesn't seem to be possible to query the asynchronous statemachine for its current state. I realize that during real execution this isn't a good thing to do, but I need this for my unit tests. In the tests I feed the statemachine with events in a controlled environment and check that the transitions and the states' behaviour are as expected. // Johan