Boost logo

Boost :

Subject: [boost] [MSM] Interrupt anonymous transitions or blocking process_events?
From: Mathias A (anlmat_at_[hidden])
Date: 2011-04-15 17:12:13


Hi there!

I have been experimenting with the MSM (Meta State Machine) and I think
it is a very nice tool!

After reading and trying most of the example code regarding the MSM I
present to you my problem. How do I interrupt blocking calls or long
running states with anonymous transitions?

Ok, here is my story.

Regarding "Defining a submachine" in the docs

(http://www.boost.org/doc/libs/1_46_1/libs/msm/doc/HTML/ch03s02.html#d0e597)

and supplied source code example

(http://www.boost.org/doc/libs/1_46_1/libs/msm/doc/HTML/examples/CompositeTutorial.cpp)

Let's say that this was a real CD player then the player would change to
the next song by itself. It would not rely on the user pushing the Next
button to change song. Now, if I implement the transition table like this:

struct transition_table : mpl::vector4
//         Start     Event         Next      Action        Guard
-----------+-------------+---------+---------------------+----------------------+
a_row <    Song1   , none        , Song2   , &pl::start_next_song >,
a_row <    Song2   , PreviousSong, Song1   , &pl::start_prev_song >,
a_row <    Song2   , none        , Song3   , &pl::start_next_song >,
a_row <    Song3   , PreviousSong, Song2   , &pl::start_prev_song >
+---------+-------------+---------+---------------------+----------------------+
 > {};

Note the "none" for anonymous transitions.

By calling p.process_event(play()); the the player will start playing
Song1 and then change to the next song by itself. But now in single
threaded mode it blocks until it reaches "Song3". So it is not possible
to process any other events during this time. In other words, it cannot
process another process_event call. The "Playing" state has a "stop"
event but calling this will not help as it will not be processed until
the MSM has reached "Song3".

In multi threaded mode
(no complete source code for this here sorry. with mutex protected
access to process_event)
thread 1:
lock(mutex)
p.process_event(play());
lock.unlock();

thread 2:
wait a few ms so we are in the middle of playing a song
lock(mutex)
p.process_event(stop());
lock.unlock();

I start the same p.process_event(play()); in thread 1. And in thread 2 I
call p.process_event(stop()); The problem with this is that the stop()
event does not get processed until it reaches Song3 because of the
blocking call in p.process_event(play());.

Perhaps I am going about this the wrong here and please tell me if it
can be done in some other much better way! I want to be able to have
automatic transitions that I can interrupt.

A not so elegant workaround:
In thread 2 access the Playing state directly and set a bool variable.
(bool externalStop_;)
Add a guard to each anonymous transition checking if the source state
has externalStop_ == true and stop the transition.
The Playing state can then create a stop event and then call
process_event(stop()) by itself.
And we have successfully injected a stop event.

Summary:
I cannot seem to get round the blocking call using only the transition
table. I really hope it can be done in a more elegant way than I did in
the workaround.

Any suggestions on how to do this?

Thank you!

Best regards,
Mathias


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk