
-----Original Message----- From: Boost-users [mailto:boost-users-bounces@lists.boost.org] On Behalf Of Andreas Huber Sent: Monday, February 25, 2013 11:43 AM To: boost-users@lists.boost.org Subject: Re: [Boost-users] boost::statechart - two async machines in one process?
[snip] I don't see why the machines should behave as you describe. Can you please post a repro?
Thanks & Regards, Andreas Huber
Happy Thursday Andreas, Apologies in advance for all the code. Simply not sure where the hints may be found. When the offending line (the_many_impl.cpp, [.create_processor]) is removed, react(the_one_init) occurs. When line 14 is restored, the react() does not occur (i.e., program appears to be hung). ./exemplar the_many_impl ctor. the_many_impl queued the the_many_init event. the_one_impl ctor. the_one_impl queued the the_one_init event. waiting for a keystroke. the_one_state_machine ctor. the_one_state_machine::initiate_impl() the_one installed_state ctor. the_one installed_state::react(the_one_init) <-- with [.create_processor] disabled k ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning from main. ~the_one_impl dtor. exemplar: /xtools/boost/i686-pc-linux-gnu/boost_1_51_0/ include/boost/thread/pthread/condition_variable.hpp:133: boost::condition_variable_any::~condition_variable_any(): Assertion `!pthread_mutex_destroy(&internal_mutex)' failed. Aborted file: the_one.hpp //^^^^^^^^^^^^^^^ #if !defined(THE_ONE_HPP_26D4F573_E462_4863_A730_79E1A8B28639) #define THE_ONE_HPP_26D4F573_E462_4863_A730_79E1A8B28639 #include <memory> namespace western_digital { class the_one_impl; class the_one { public: the_one(); virtual ~the_one(); private: std::unique_ptr< the_one_impl > impl_; }; // class the_one } // namespace western_digital #endif // THE_ONE_HPP_26D4F573_E462_4863_A730_79E1A8B28639 file: the_one.cpp //^^^^^^^^^^^^^^^ #include <string> #include "the_one/the_one.hpp" #include "the_one/the_one_impl.hpp" namespace fw = western_digital; fw::the_one::the_one() : impl_( new fw::the_one_impl() ) {} fw::the_one::~the_one() {} file: the_one_impl.hpp //^^^^^^^^^^^^^^^^^^^^ #if !defined(THE_ONE_IMPL_HPP_EA676320_C9EC_4A09_BCA4_DF5E40FDC262) #define THE_ONE_HPP_EA676320_C9EC_4A09_BCA4_DF5E40FDC262 #include <memory> #include <string> #include <iostream> #include "the_one/the_one_state_machine.hpp" namespace sc = boost::statechart; namespace mpl = boost::mpl; namespace western_digital { class the_one_impl { public: the_one_impl(); virtual ~the_one_impl() { std::cout << "~the_one_impl dtor." << std::endl; } the_one_scheduler_t the_one_scheduler_; sc::fifo_scheduler<>::processor_handle sm_; boost::thread the_one_thread_; }; // class the_one_impl } // western_digital #endif // #if !defined(THE_ONE_IMPL_HPP_EA676320_C9EC_4A09_BCA4_DF5E40FDC262) file: the_one_impl.cpp //^^^^^^^^^^^^^^^^^^^^ #include "the_one/the_one_impl.hpp" namespace fw = western_digital; fw::the_one_impl::the_one_impl() : the_one_scheduler_(true), sm_( the_one_scheduler_.create_processor< fw::the_one_state_machine_t >() ), the_one_thread_() { std::cout << "the_one_impl ctor." << std::endl; the_one_scheduler_.initiate_processor( sm_ ); the_one_scheduler_.queue_event( sm_, MakeIntrusive( new fw::the_one_init() ) ); std::cout << "the_one_impl queued the the_one_init event." << std::endl; boost::thread temp_thread( boost::bind( &sc::fifo_scheduler<>::operator(), &the_one_scheduler_, 0 ) ); the_one_thread_.swap( temp_thread ); } file: the_one_state_machine.hpp //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #if !defined(THE_ONE_STATE_MACHINE_HPP_CE0C147D_8C95_4EAB_B7BD_6C527E9332F5) #define THE_ONE_STATE_MACHINE_HPP_CE0C147D_8C95_4EAB_B7BD_6C527E9332F5 #include <stdexcept> #include <system_error> #include <string> #include <iostream> #include <iterator> #include <boost/statechart/event.hpp> #include <boost/statechart/fifo_scheduler.hpp> #include <boost/statechart/asynchronous_state_machine.hpp> #include <boost/statechart/custom_reaction.hpp> #include <boost/statechart/state.hpp> #include <boost/intrusive_ptr.hpp> #include <boost/config.hpp> #include <boost/intrusive_ptr.hpp> #include <boost/mpl/list.hpp> #include <boost/function.hpp> #include <boost/filesystem.hpp> #include <boost/thread/thread.hpp> #include <boost/lexical_cast.hpp> #include <boost/filesystem.hpp> #include <boost/bind.hpp> #include "the_one/the_one_events.hpp" namespace sc = boost::statechart; namespace mpl = boost::mpl; using std::cout; using std::endl; #ifdef CUSTOMIZE_MEMORY_MANAGEMENT typedef boost::fast_pool_allocator< int > the_one_allocator_t; typedef sc::fifo_scheduler< sc::fifo_worker< the_one_allocator_t >, the_one_allocator_t > the_one_scheduler_t; #else typedef std::allocator< void > the_one_allocator_t; typedef sc::fifo_scheduler<> the_one_scheduler_t; #endif namespace { template< class T > boost::intrusive_ptr< T > MakeIntrusive( T * ptr ) { return boost::intrusive_ptr< T >( ptr ); } } namespace western_digital { struct installed_state; struct resolved_state; struct the_one_state_machine; typedef struct the_one_state_machine : sc::asynchronous_state_machine< the_one_state_machine, installed_state, the_one_scheduler_t, the_one_allocator_t > { the_one_state_machine( my_context ctx ) : my_base( ctx ) { cout << "the_one_state_machine ctor." << endl; } virtual ~the_one_state_machine() {} virtual void initiate_impl(); } the_one_state_machine_t; struct installed_state : sc::state< installed_state, the_one_state_machine > { typedef mpl::list< sc::custom_reaction< the_one_init >, sc::custom_reaction< the_one_start > > reactions; installed_state( my_context ctx ) : my_base( ctx ) { cout << "the_one installed_state ctor." << endl; } virtual ~installed_state() { cout << "entered the_one installed_state dtor." << endl; } sc::result react( const the_one_init & ) { cout << "the_one installed_state::react(the_one_init)" << endl; return( discard_event() ); } sc::result react( const the_one_start & ) { cout << "the_one installed_state::react(the_one_start)" << endl; return( discard_event() ); } }; // installed_state struct resolved_state : sc::state< resolved_state, the_one_state_machine > { typedef mpl::list< sc::custom_reaction< the_one_stop > > reactions; resolved_state( my_context ctx ) : my_base( ctx ) { cout << "the_one_state_machine: resolved_state ctor." << endl; } virtual ~resolved_state() { cout << "the_one_state_machine: resolved_state dtor." << endl; } sc::result react( const the_one_stop & ) { cout << "the_one resolved_state::react(the_one_stop)" << endl; return( discard_event() ); } }; } // western_digital #endif // THE_ONE_STATE_MACHINE_HPP_CE0C147D_8C95_4EAB_B7BD_6C527E9332F5 file: the_one_state_machine.cpp //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #include "the_one/the_one_state_machine.hpp" namespace sc = boost::statechart; namespace mpl = boost::mpl; namespace fw = western_digital; using std::cout; using std::endl; void fw::the_one_state_machine::initiate_impl() { std::cout << "the_one_state_machine::initiate_impl()" << std::endl; sc::state_machine< fw::the_one_state_machine, fw::installed_state, the_one_allocator_t >::initiate(); } file: the_many.hpp //^^^^^^^^^^^^^^^^ #if !defined(THE_MANY_HPP_5BE2EC5B_0251_4BE1_9302_A046BAD8E174) #define THE_MANY_HPP_5BE2EC5B_0251_4BE1_9302_A046BAD8E174 #include <memory> namespace western_digital { struct the_many { the_many(); virtual ~the_many(); } the_many_t; // struct the_many } // western_digital #endif // THE_MANY_HPP_5BE2EC5B_0251_4BE1_9302_A046BAD8E174 file: the_many.cpp //^^^^^^^^^^^^^^^^ #include "the_many/the_many.hpp" namespace fw = western_digital; fw::the_many::the_many() {} fw::the_many::~the_many() {} file: the_many_impl.hpp //^^^^^^^^^^^^^^^^^^^^^ #if !defined(THE_MANY_IMPL_HPP_E8FDA315_8707_4FDF_AD41_234F6EAC25AF) #define THE_MANY_IMPL_HPP_E8FDA315_8707_4FDF_AD41_234F6EAC25AF #include <memory> #include <string> #include <iostream> #include "the_many/the_many_state_machine.hpp" namespace sc = boost::statechart; namespace mpl = boost::mpl; namespace western_digital { class the_many_impl { public: the_many_impl(); virtual ~the_many_impl() { std::cout << "~the_many_impl dtor." << std::endl; } the_many_scheduler_t the_many_scheduler_; sc::fifo_scheduler<>::processor_handle sm_; boost::thread the_many_thread_; }; // class the_many_impl } // namespace western_digital #endif // THE_MANY_IMPL_HPP_E8FDA315_8707_4FDF_AD41_234F6EAC25AF file: the_many_impl.cpp //^^^^^^^^^^^^^^^^^^^^^ #include "the_many/the_many_impl.hpp" namespace fw = western_digital; fw::the_many_impl::the_many_impl() : the_many_scheduler_(true), // Following line 'causes' the problem to manifest. Remove and problem disappears. sm_(the_many_scheduler_.create_processor< fw::the_many_state_machine_t >() ), //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// the_many_thread_() { std::cout << "the_many_impl ctor." << std::endl; // If sm_ is initialized as sm_(), the following assignment also creates the problem. //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //the_many_scheduler_.initiate_processor( sm_ ); the_many_scheduler_.queue_event( sm_, MakeIntrusive( new fw::the_many_init() ) ); std::cout << "the_many_impl queued the the_many_init event." << std::endl; // The problem occurs whether or not the following two lines are included in the build. boost::thread temp_thread( boost::bind( &sc::fifo_scheduler<>::operator(), &the_many_scheduler_, 0 ) ); the_many_thread_.swap( temp_thread ); //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ } file: the_one_state_machine.hpp //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #if !defined(THE_ONE_STATE_MACHINE_HPP_CE0C147D_8C95_4EAB_B7BD_6C527E9332F5) #define THE_ONE_STATE_MACHINE_HPP_CE0C147D_8C95_4EAB_B7BD_6C527E9332F5 #include <stdexcept> #include <system_error> #include <string> #include <iostream> #include <iterator> #include <boost/statechart/event.hpp> #include <boost/statechart/fifo_scheduler.hpp> #include <boost/statechart/asynchronous_state_machine.hpp> #include <boost/statechart/custom_reaction.hpp> #include <boost/statechart/state.hpp> #include <boost/intrusive_ptr.hpp> #include <boost/config.hpp> #include <boost/intrusive_ptr.hpp> #include <boost/mpl/list.hpp> #include <boost/function.hpp> #include <boost/filesystem.hpp> #include <boost/thread/thread.hpp> #include <boost/lexical_cast.hpp> #include <boost/filesystem.hpp> #include <boost/bind.hpp> #include "the_one/the_one_events.hpp" namespace sc = boost::statechart; namespace mpl = boost::mpl; using std::cout; using std::endl; #ifdef CUSTOMIZE_MEMORY_MANAGEMENT typedef boost::fast_pool_allocator< int > the_one_allocator_t; typedef sc::fifo_scheduler< sc::fifo_worker< the_one_allocator_t >, the_one_allocator_t > the_one_scheduler_t; #else typedef std::allocator< void > the_one_allocator_t; typedef sc::fifo_scheduler<> the_one_scheduler_t; #endif namespace { template< class T > boost::intrusive_ptr< T > MakeIntrusive( T * ptr ) { return boost::intrusive_ptr< T >( ptr ); } } namespace western_digital { struct installed_state; struct resolved_state; struct the_one_state_machine; typedef struct the_one_state_machine : sc::asynchronous_state_machine< the_one_state_machine, installed_state, the_one_scheduler_t, the_one_allocator_t > { the_one_state_machine( my_context ctx ) : my_base( ctx ) { cout << "the_one_state_machine ctor." << endl; } virtual ~the_one_state_machine() {} virtual void initiate_impl(); } the_one_state_machine_t; struct installed_state : sc::state< installed_state, the_one_state_machine > { typedef mpl::list< sc::custom_reaction< the_one_init >, sc::custom_reaction< the_one_start > > reactions; installed_state( my_context ctx ) : my_base( ctx ) { cout << "the_one installed_state ctor." << endl; } virtual ~installed_state() { cout << "entered the_one installed_state dtor." << endl; } sc::result react( const the_one_init & ) { cout << "the_one installed_state::react(the_one_init)" << endl; return( discard_event() ); } sc::result react( const the_one_start & ) { cout << "the_one installed_state::react(the_one_start)" << endl; return( discard_event() ); } }; // installed_state struct resolved_state : sc::state< resolved_state, the_one_state_machine > { typedef mpl::list< sc::custom_reaction< the_one_stop > > reactions; resolved_state( my_context ctx ) : my_base( ctx ) { cout << "the_one_state_machine: resolved_state ctor." << endl; } virtual ~resolved_state() { cout << "the_one_state_machine: resolved_state dtor." << endl; } sc::result react( const the_one_stop & ) { cout << "the_one resolved_state::react(the_one_stop)" << endl; return( discard_event() ); } }; } // western_digital #endif // THE_ONE_STATE_MACHINE_HPP_CE0C147D_8C95_4EAB_B7BD_6C527E9332F5 file: the_one_state_machine.cpp //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #include "the_one/the_one_state_machine.hpp" namespace sc = boost::statechart; namespace mpl = boost::mpl; namespace fw = western_digital; using std::cout; using std::endl; void fw::the_one_state_machine::initiate_impl() { std::cout << "the_one_state_machine::initiate_impl()" << std::endl; sc::state_machine< fw::the_one_state_machine, fw::installed_state, the_one_allocator_t >::initiate(); } file: the_many_state_machine.hpp //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #if !defined(THE_MANY_STATE_MACHINE_HPP_40CB9DF6_2147_40CD_8C68_20B3AC9D479E) #define THE_MANY_STATE_MACHINE_HPP_40CB9DF6_2147_40CD_8C68_20B3AC9D479E #include <stdexcept> #include <system_error> #include <string> #include <iostream> #include <iterator> #include <boost/statechart/event.hpp> #include <boost/statechart/fifo_scheduler.hpp> #include <boost/statechart/asynchronous_state_machine.hpp> #include <boost/statechart/custom_reaction.hpp> #include <boost/statechart/state.hpp> #include <boost/intrusive_ptr.hpp> #include <boost/config.hpp> #include <boost/intrusive_ptr.hpp> #include <boost/mpl/list.hpp> #include <boost/function.hpp> #include <boost/thread/thread.hpp> #include <boost/lexical_cast.hpp> #include <boost/filesystem.hpp> #include <boost/filesystem/fstream.hpp> #include <boost/bind.hpp> #include "the_many/the_many_events.hpp" namespace sc = boost::statechart; namespace mpl = boost::mpl; using std::cout; using std::endl; #ifdef CUSTOMIZE_MEMORY_MANAGEMENT typedef boost::fast_pool_allocator< int > the_many_allocator_t; typedef sc::fifo_scheduler< sc::fifo_worker< the_many_allocator_t >, the_many_allocator_t > the_many_scheduler_t; #else typedef std::allocator< void > the_many_allocator_t; typedef sc::fifo_scheduler<> the_many_scheduler_t; #endif namespace { template< class T > boost::intrusive_ptr< T > MakeIntrusive( T * ptr ) { return boost::intrusive_ptr< T >( ptr ); } } namespace western_digital { struct installed_state; struct resolved_state; struct the_many_state_machine; typedef struct the_many_state_machine : sc::asynchronous_state_machine< the_many_state_machine, installed_state, the_many_scheduler_t, the_many_allocator_t > { the_many_state_machine( my_context ctx ) : my_base( ctx ) { cout << "the_many_state_machine ctor." << endl; } virtual ~the_many_state_machine() { std::cout << "the_many_state_machine dtor." << std::endl; } virtual void initiate_impl(); } the_many_state_machine_t; struct installed_state : sc::state< installed_state, the_many_state_machine > { typedef mpl::list< sc::custom_reaction< the_many_init >, sc::custom_reaction< the_many_start > > reactions; installed_state( my_context ctx ) : my_base( ctx ) { std::cout << "the_many installed_state ctor." << endl; } virtual ~installed_state() { std::cout << "entered the_many installed_state dtor." << endl; } sc::result react( const the_many_init & ) { std::cout << "the_many installed_state::react(the_many_init)" << endl; return( discard_event() ); } sc::result react( const the_many_start & ) { std::cout << "the_many installed_state::react(the_many_start)" << endl; return( discard_event()); } }; // installed_state struct resolved_state; struct resolved_state : sc::state< resolved_state, the_many_state_machine > { typedef mpl::list< sc::custom_reaction< the_many_init >, sc::custom_reaction< the_many_start > > reactions; sc::result react( const the_many_init & ) { cout << "the_many resolved_state::react(the_many_init)" << endl; return( discard_event()); } sc::result react( const the_many_start & ) { cout << "the_many resolved_state::react(the_many_start)" << endl; return( discard_event()); } }; } // western_digital #endif // THE_MANY_STATE_MACHINE_HPP_40CB9DF6_2147_40CD_8C68_20B3AC9D479E file: the_many_state_machine.cpp //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #include <sstream> #include <iostream> #include <fstream> #include <regex> #include "the_many/the_many_state_machine.hpp" namespace sc = boost::statechart; namespace mpl = boost::mpl; namespace fw = western_digital; void fw::the_many_state_machine::initiate_impl() { std::cout << "the_many_state_machine::initiate_impl()" << std::endl; sc::state_machine< fw::the_many_state_machine, fw::installed_state, the_many_allocator_t >::initiate(); } file: main.cpp //^^^^^^^^^^^^ #include <iostream> #include <boost/intrusive_ptr.hpp> #include <boost/thread/thread.hpp> #include <boost/lexical_cast.hpp> #include <boost/filesystem.hpp> #include "the_one/the_one.hpp" #include "the_one/the_one_state_machine.hpp" namespace fw = western_digital; namespace fs = boost::filesystem; int main() { fw::the_one f; char x; std::cout << "waiting for a keystroke." << std::endl; std::cin >> x; std::cout << "returning from main." << std::endl; return(0); } With Highest Regards, Dick