
Hi, i try to build a easy statechart to learn and understand how to use boost::statechart. All i used until today was "homemade" statemachines. At some states i need a "Execute" function. In the FAQ i read, that therefore i should use a a thread and send there an event to the statemachine and process this event. So i wrote a timerclass which uses a thread to process an event via signals2. <code> ----------- timeout.h #ifndef __timeout_h__ #define __timeout_h__ #include <boost/thread.hpp> #include <boost/signals2.hpp> #include <boost/date_time/posix_time/posix_time.hpp> class Timeout { public: typedef boost::signals2::signal<void ()> signal_t; Timeout() : mp_thread(0) { lock lk(m_monitor); } ~Timeout() { lock lk(m_monitor); Terminate(); } boost::signals2::connection connect(const signal_t::slot_type &subscriber) { lock lk(m_monitor); return m_sig.connect(subscriber); } void Start(boost::posix_time::time_duration delta_time, bool repeat = false) { lock lk(m_monitor); if (mp_thread) { Terminate(); } m_repeat = repeat; m_delta_time = delta_time; mp_thread = new boost::thread( boost::bind( &Timeout::Execute, this)); } void Stop() { lock lk(m_monitor); if (mp_thread) { Terminate(); } } private: typedef boost::mutex::scoped_lock lock; void Execute() { try { do { boost::this_thread::sleep(m_delta_time); { lock lk(m_monitor); m_sig(); } } while (m_repeat); } catch(boost::thread_exception& /* e */) { // we got interrupted } } void Terminate() { if (mp_thread) { mp_thread->interrupt(); delete mp_thread; mp_thread = 0; } } signal_t m_sig; boost::thread* mp_thread; boost::mutex m_monitor; boost::posix_time::time_duration m_delta_time; bool m_repeat; }; ----------- main.cpp // SimpleBoostSCProblem // main.cpp #include "Timeout.h" #include <boost/statechart/event.hpp> #include <boost/statechart/transition.hpp> #include <boost/statechart/custom_reaction.hpp> #include <boost/statechart/state_machine.hpp> #include <boost/statechart/simple_state.hpp> #include <boost/statechart/state.hpp> #include <boost/mpl/list.hpp> namespace MyTest { namespace sc = boost::statechart; namespace mpl = boost::mpl; // Our objects struct Obj1 {}; // -------------------------------------------------- // Events // -------------------------------------------------- struct EvWork : sc::event< EvWork > {}; struct EvExit : sc::event< EvExit > {}; // -------------------------------------------------- // Forward deklaration of states // -------------------------------------------------- struct Active; struct DoStuff1; struct DoStuff2; struct Exit; // -------------------------------------------------- // Statemachine // -------------------------------------------------- struct TestMachine : sc::state_machine< TestMachine, Active > { TestMachine() { } ~TestMachine() { } }; // -------------------------------------------------- // States // -------------------------------------------------- // TestMachine / Active struct Active : sc::state<Active, TestMachine, mpl::list< DoStuff1 > > { typedef mpl::list< sc::transition< EvExit , Exit > > reactions; Active(my_context ctx) : my_base(ctx) { m_worker_connection = m_worker.connect(boost::bind(&Active::ProcessEvent<EvWork>, this)); } ~Active() { m_worker.Stop(); m_worker_connection.disconnect(); } template<typename ev> void ProcessEvent() { outermost_context().process_event(ev()); } Timeout m_worker; private: boost::signals2::connection m_worker_connection; }; // TestMachine / Active / DoStuff1 struct DoStuff1 : sc::state<DoStuff1, Active > { typedef mpl::list< sc::transition< EvWork, DoStuff2 > > reactions; DoStuff1(my_context ctx) : my_base(ctx) { // start work timeout : Repeat every 10 ms context< Active >().m_worker.Start(boost::posix_time::milliseconds(100)); } ~DoStuff1() { } }; // TestMachine / Active / DoStuff2 struct DoStuff2 : sc::state<DoStuff2, Active > { typedef mpl::list< sc::custom_reaction< EvWork > > reactions; DoStuff2(my_context ctx) : my_base(ctx) { // start work timeout : Repeat every 10 ms context< Active
().m_worker.Start(boost::posix_time::milliseconds(1),true); } ~DoStuff2() { }
sc::result react( const EvWork & ) { // do stuff // .. // Nothing more to do with this event return discard_event(); } }; // TestMachine / Exit struct Exit : sc::state<Exit, TestMachine > { Exit(my_context ctx) : my_base(ctx) { } ~Exit() { } }; }; int main(int argc, char* argv[]) { MyTest::TestMachine machine; machine.initiate(); boost::this_thread::sleep(boost::posix_time::seconds(10)); machine.process_event(MyTest::EvExit()); return 0; } </code> It the statemachine exits, i get constantly crashes in the process_event<EvWork>() function, because the statemachine itself got destructed and outermost_context() is no more vaild, but the state which holds my timeout object (and the thread) did not yet got destructed and therefore the thread stopped. I dont have an idea to solve that problem. There is an assertion: "get_pointer( pOutermostUnstableState_ )==0" in state_machine.hpp. It does only happen if there was a transition from one state (DoStuff1) to DoState2. Thanks in advance! Georg Gast P.S.: My system: Windows XP / Visualstudio 2008 / Boost 1.40.0