
Hi Christophe, Thank you for the helpful reply! <snip>
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.
You have to use run-to-completion. Base your design on short-terms events fed to the state machine, which triggers work and reacts to changes in forms of other events. In your case, one possibility would be to have the state machine delegate (post) some work upon state entry or transition action to a thread, then posting a new task upon state exit, etc. Make your state machine be serviced by only one thread, triggering work and reacting to events. Trust me on that one, having a state machine serviced by 2 threads is a good receipt for headaches ;-) If you know boost::asio, it's a bit like the async_xxx methods, trigger some work and get ready for the next action (which would be a callback, to continue with this asio example).
That helped me alot doing it that way. Thank you! It was a struggle before I realized how to call a process_event(...) from within a member function. I hope I am doing it the right way :-) I also tried adding boost::signals2::signal<void ()> sig; to the statemachine but my compiler did not like that at all (noncopyable errors). So I stayed with a mutex and a condition variable. The way I did it can be improved I am sure... Anyway, you can see an outline below of how I did this. Perhaps this is an ok way doing it? ---------------------------- cdplayer_statemachine.h struct player_ : ... { boost::mutex event_mutex_; boost::thread thread_; boost::condition_variable_any cond_; bool trigger_; void next_song(); void playing_thread(); ... //I choose to start the thread in the ctor... player_():thread_(boost::thread(&player_::playing_thread, this)) {} ... //action struct play_song { template <class EVT,class FSM,class SourceState,class TargetState> void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& ) { std::cout << "starting to play song "<< current_name_ <<std::endl; //triggers the thread to leave its waiting state fsm.next_song(); } }; ... //in transition_table //NextSong event is generated in the playing_thread Row < Playing , NextSong , Playing , play_song , exists_next >, Row < Playing , NextSong , Stopped , stop_playing , no_more_songs >, Row < Playing , Stop , Stopped , stop_playing >, //... ... }; // Pick a back-end typedef msm::back::state_machine<player_> player; --------------------------- cdplayer_statemachine.cpp void player_::next_song() { trigger_ = true; cond_.notify_one(); } void player_::playing_thread() { while(running_) { boost::mutex::scoped_lock trigg_lock(trigg_mutex); while(!trigger_) cond_.wait(trigg_lock); trigger_ = false; //Simulate playing song... //The state machine can now react to other events like Stop() //for example. boost::this_thread::sleep(boost::posix_time::millisec(2000)); boost::mutex::scoped_lock lock(event_mutex_); //This is how you post a process_event from a member function. // note: the "player" here is not the same as "player_" !! // this "player" is the typedef choosen back-end name. (static_cast<player*>(this))->process_event(NextSong()); } } Regards, Mathias