-----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
#include <string>
#include <iostream>
#include <iterator>
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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
#include <string>
#include <iostream>
#include <iterator>
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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
#include <string>
#include <iostream>
#include <iterator>
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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
#include
#include
#include
#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