Boost logo

Boost Users :

Subject: Re: [Boost-users] boost::statechart - two async machines in one process?
From: Dick Bridges (Dick.Bridges_at_[hidden])
Date: 2013-02-28 15:37:55


-----Original Message-----
From: Boost-users [mailto:boost-users-bounces_at_[hidden]] On Behalf Of Andreas Huber
Sent: Monday, February 25, 2013 11:43 AM
To: boost-users_at_[hidden]
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


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