|
Boost Users : |
Subject: [Boost-users] [Boost Statechart] Execute Function
From: Georg Gast (schorsch_76_at_[hidden])
Date: 2009-09-29 15:20:03
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
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net