3

boost::statechart::asynchronous_state_machine を作成する必要があり、それを外部から「破棄」できる必要があります。ドキュメントで、destroy_processor を呼び出して終了する必要があることがわかりました。問題は、これらのメソッドがマシン イベント キューにイベントを挿入するだけであるため、これらのイベントが処理される前に fifo_scheduler<> を削除すると、エラーが発生することです... (以下の例を参照)

問題は...非同期_状態_マシンが「終了」し、 fifo_scheduler<> を「削除」しても安全であることをどのように知ることができますか?

#include <boost/statechart/event.hpp>
#include <boost/statechart/state.hpp>
#include <boost/statechart/custom_reaction.hpp>

#include <boost/statechart/asynchronous_state_machine.hpp>
#include <boost/statechart/fifo_scheduler.hpp>


#include <boost/intrusive_ptr.hpp>

#include <boost/asio/io_service.hpp>
#include <boost/thread/thread.hpp>


#include <iostream>


namespace sc = boost::statechart;
// States
struct Stop;
struct Running;
struct Playing;
struct Paused;

// Events
struct EvPlay : public sc::event<EvPlay>{};
struct EvStop : public sc::event<EvStop>{};
struct EvPause : public sc::event<EvPause>{};

// State machine and states definition
struct MyMachine : public sc::asynchronous_state_machine<MyMachine,Stop>
{
public:
  MyMachine (my_context ctx, const unsigned int& ai_id)
    : my_base(ctx)
    , m_id(ai_id)
  {
    std::cout << "th["<< boost::this_thread::get_id()  << "]"
              << "MyMachine["<< m_id << "]: Constructor  "
              << std::endl; 
  }

  ~MyMachine (void)
  {
    std::cout << "th["<< boost::this_thread::get_id()  << "]"
              << "MyMachine["<< m_id << "]: Destructor  "
              << std::endl; 
  }

  unsigned int id(void)const
  {
    return m_id;
  }

private:
  unsigned int m_id;
};


struct Stop : sc::state<Stop,MyMachine>
{
public:

  typedef sc::custom_reaction<EvPlay> reactions;

  Stop(my_context ctx)
    : my_base(ctx)
    , m_id(context<MyMachine>().id())
  {
    std::cout << "th["<< boost::this_thread::get_id()  << "]"
              << "OnEntry["<< m_id << "]: Stop  "
              << std::endl; 
  }
  ~Stop(void)
  {
    std::cout << "th["<< boost::this_thread::get_id()  << "]"
              << "OnExit["<< m_id << "]: Stop  "
              << std::endl; 
  }

  sc::result react(const EvPlay&)
  {
    std::cout << "th["<< boost::this_thread::get_id()  << "]"
              << "Stop::Event["<< m_id << "]: EvPlay  "
              << std::endl;
    return transit<Running>();
  }

private:
  unsigned int m_id;
};

struct Running : sc::state <Running, MyMachine, Playing>
{
public:

  typedef sc::custom_reaction<EvStop> reactions;

  Running(my_context ctx)
    : my_base(ctx)
    , m_id(context<MyMachine>().id())
  {
    std::cout << "th["<< boost::this_thread::get_id()  << "]"
              << "OnEntry["<< m_id << "]: Running  "
              << std::endl; 
  }

  ~Running(void)
  {
    std::cout << "th["<< boost::this_thread::get_id()  << "]"
              << "OnExit["<< m_id << "]: Running  "
              << std::endl; 
  }

  sc::result react(const EvStop&)
  {
    std::cout << "th["<< boost::this_thread::get_id()  << "]"
              << "Running::Event["<< m_id << "]: EvStop  "
              << std::endl;
    return transit<Stop>();
  }
private:
  unsigned int m_id;
};

struct Playing : sc::state<Playing, Running>
{
public:

  typedef sc::custom_reaction<EvPause> reactions;

  Playing(my_context ctx)
    : my_base(ctx)
    , m_id(context<MyMachine>().id())
  {
    std::cout << "th["<< boost::this_thread::get_id()  << "]"
              << "OnEntry["<< m_id << "]: Playing  "
              << std::endl; 
  }

  ~Playing(void)
  {
    std::cout << "th["<< boost::this_thread::get_id()  << "]"
              << "OnExit["<< m_id << "]: Playing  "
              << std::endl; 
  }

  sc::result react(const EvPause&)
  {
    std::cout << "th["<< boost::this_thread::get_id()  << "]"
              << "Playing::Event["<< m_id << "]: EvPause  "
              << std::endl;
    return transit<Paused>();
  }

private:
  unsigned int m_id;
};

struct Paused : sc::state<Paused, Running>
{
public:

  typedef sc::custom_reaction<EvPause> reactions;

  Paused(my_context ctx)
    : my_base(ctx)
    , m_id(context<MyMachine>().id())
  {
    std::cout << "th["<< boost::this_thread::get_id()  << "]"
              << "OnEntry["<< m_id << "]: Paused  "
              << std::endl; 
  }

  ~Paused(void)
  {
    std::cout << "th["<< boost::this_thread::get_id()  << "]"
              << "OnExit["<< m_id << "]: Paused  "
              << std::endl; 
  }

  sc::result react(const EvPause&)
  {
    std::cout << "th["<< boost::this_thread::get_id()  << "]"
              << "Paused::Event["<< m_id << "]: EvPause  "
              << std::endl;
    return transit<Playing>();
  }

private:
  unsigned int m_id;
};

// ---------------------------------------------------------------------------


int main(void)
{

  // create threadpool and ioservice
  boost::thread_group threadPool;
  boost::asio::io_service ioService;

  // create work for ioservice
  boost::asio::io_service::work* work (new boost::asio::io_service::work(ioService));

  // create threads
  threadPool.create_thread(boost::bind(&boost::asio::io_service::run, &ioService));


  // create machines
  sc::fifo_scheduler<>* sch1(new sc::fifo_scheduler<>(true));
  sc::fifo_scheduler<>::processor_handle handle1 (sch1->create_processor<MyMachine>(1));


  //initiate machines
  sch1->initiate_processor(handle1);


  ioService.post(boost::bind(&sc::fifo_scheduler<>::operator(),sch1,0));



  boost::this_thread::sleep(boost::posix_time::milliseconds(1000));

  std::cout << "main_th["<< boost::this_thread::get_id()  << "]:" << "destroying ... " << std::endl;
  sch1->destroy_processor(handle1);
  sch1->terminate();
  std::cout << "main_th["<< boost::this_thread::get_id()  << "]:" << " ... destroyed " << std::endl;

  // some time to process the events ( not a solution ) ...
  // comment this line to get the error.
  boost::this_thread::sleep(boost::posix_time::milliseconds(5000));

  std::cout << "main_th["<< boost::this_thread::get_id()  << "]:" << "deleting ... "<< std::endl;
  delete sch1;
  sch1 = 0;
  std::cout << "main_th["<< boost::this_thread::get_id()  << "]:" << " ... deleted"<< std::endl;



  // kill work to exit
  delete work;
  work = 0;

  //wait for all threads to exit
  threadPool.join_all();

  return 0;
}
4

1 に答える 1