Boost StateChart實現狀態機----秒錶例程

horsetail發表於2017-09-26

 

Boost 提供了狀態機的實現介面,採用了CRTP技術實現,下面以秒錶為例子實現一個狀態機,這是一個官方的例子,也可以參考資料:Boost Statechart 庫,狀態機的狀態轉換圖如下所示:

實現程式碼如下: 

#include <stdio.h>
#include <stdlib.h>

#include <iostream> // std::cout
#include <thread>   // std::thread
#include <string>
#include <vector>
#include <ros/ros.h>
#include <boost/statechart/state_machine.hpp>
#include <boost/statechart/state.hpp>
#include <boost/statechart/event.hpp>
#include <boost/statechart/transition.hpp>
#include <boost/statechart/custom_reaction.hpp>
#include <boost/range/irange.hpp>
#include <boost/thread/thread.hpp>

#include <ctime>

using namespace std;
namespace sc = boost::statechart;

class EvStartStop : public sc::event<EvStartStop>
{
};
class EvReset : public sc::event<EvReset>
{
};

/*虛類,用於狀態機獲取狀態*/
class IElapsedTime
{
 public:
  virtual double elapsedTime() const = 0;
  virtual ~IElapsedTime(){};
};

class Active;
/*秒錶,狀態機*/
class StopWatch : public sc::state_machine<StopWatch, Active>
{
 public:
  double elapsedTime() const
  {
    return state_cast<const IElapsedTime &>().elapsedTime();
  }
};

class Stopped;
/*活動狀態*/
class Active : public IElapsedTime, public sc::state<Active, StopWatch, Stopped>
{
 public:
  typedef sc::transition<EvReset, Active> reactions;

  Active(my_context ctx)
      : my_base(ctx),
        elapsed_time_(0)
  {
    cout << "Entry Active" << endl;
  }
  ~Active()
  {
    cout << "Exit Active" << endl;
  }

  double elapsedTime() const
  {
    return elapsed_time_;
  }
  double& elapsedTime()
  {
    return elapsed_time_;
  }

 private:
  double elapsed_time_;
};

/*計時狀態*/
class Running : public IElapsedTime, public sc::state<Running, Active>
{
 public:
  typedef sc::transition<EvStartStop, Stopped> reactions;
  Running(my_context ctx)
      : my_base(ctx),
        start_time_(std::time(0))
  {
    cout << "Entry Running" << endl;
  }
  ~Running()
  {
    context<Active>().elapsedTime() = elapsedTime();
    cout << "Exit Running" << endl;
  }
  virtual double elapsedTime() const
  {
    return context<Active>().elapsedTime()
        + std::difftime(std::time(0), start_time_);
  }
 private:
  std::time_t start_time_;
};

/*停止狀態*/
class Stopped : public IElapsedTime, public sc::state<Stopped, Active>
{
 public:
  typedef sc::transition<EvStartStop, Running> reactions;
  Stopped(my_context ctx)
      : my_base(ctx)
  {
    cout << "Entry Stopped" << endl;
  }
  ~Stopped()
  {
    cout << "Exit Stopped" << endl;
  }
  virtual double elapsedTime() const
  {
    return context<Active>().elapsedTime();
  }

};

int main(int argc, char** argv)
{
  StopWatch myWatch;
  myWatch.initiate();
  cout << "---" << endl;

  myWatch.process_event(EvStartStop());
  for(int i = 0; i < 10; i++)
  {
    boost::this_thread::sleep(boost::posix_time::seconds(1));  //休眠1秒
    std::cout << "time:" << myWatch.elapsedTime() << "\n";
  }
  myWatch.process_event(EvStartStop());
  boost::this_thread::sleep(boost::posix_time::seconds(1));
  std::cout << "current time:" << myWatch.elapsedTime() << "\n";
  cout << "---" << endl;
  myWatch.process_event(EvReset());
  std::cout << "reset time:" << myWatch.elapsedTime() << "\n";
  cout << "---" << endl;
  return 0;
}

 執行效果如下:

Entry Active
Entry Stopped
---
Exit Stopped
Entry Running
time:1
time:2
time:3
time:4
time:5
time:6
time:7
time:8
time:9
time:10
Exit Running
Entry Stopped
current time:10
---
Exit Stopped
Exit Active
Entry Active
Entry Stopped
reset time:0
---
Exit Stopped
Exit Active

 

相關文章