如何知道异步状态机何时终止。 (升压::状态图)

Posted

技术标签:

【中文标题】如何知道异步状态机何时终止。 (升压::状态图)【英文标题】:How to know when an asynchronous state machine has terminated. (boost::statechart) 【发布时间】:2015-03-20 03:55:39 【问题描述】:

我需要创建一个 boost::statechart::asynchronous_state_machine 并且我需要能够在外部“销毁”它。 我在文档中发现我应该调用 destroy_processor 并终止执行它。问题是这些方法只是在机器事件队列中插入一个事件,因此,如果我在处理这些事件之前删除 fifo_scheduler,则会引发错误......(参见下面的示例)

问题是......我怎么知道asynchronous_state_machine什么时候已经“终止”并且可以安全地“删除”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;

【问题讨论】:

这里完全相同的问题。在拥有 fifo_scheduler 的对象的析构函数中,我如何才能阻塞直到知道机器已经终止? 【参考方案1】:

您可以通过 terminated() 函数检查 fifo_scheduler 对象内部的状态机状态。

在你的代码中你可以做

if(sch1->terminated()) 
    // do something for the state machine has terminated
    // destroy_processor() and terminate() or something else

您将使用 do 或 for 循环来解决此问题。

【讨论】:

以上是关于如何知道异步状态机何时终止。 (升压::状态图)的主要内容,如果未能解决你的问题,请参考以下文章

HTML - 我如何知道所有帧何时加载?

UML中状态机图概念

iOS:如何判断应用程序何时暂停? [复制]

操作系统如何知道进程何时应该处于阻塞状态?

node.js 进程如何知道何时停止?

从 redux 更改状态后如何以及何时调用反应组件方法