【boost::statechart】2状态机

 boost::statechart

Ceph在处理PG的状态转换时,使用了boost库提供的statechart状态机。因此,这里先简单介绍一下statechart状态机的基本概念和涉及的相关知识,以便更好地理解Peering过程PG的状态转换流程。

3.1 状态

在statechart里,状态的定义有两种方式:

没有子状态情况下的状态定义:

struct Reset : boost::statechart::state< Reset, RecoveryMachine >, NamedState {
};

定义一个状态需要继承boost::statechart::simple_state或者boost::statechart::state类。上面Reset状态继承了boost::statechart::state类。该类的模板参数中,第一个参数为状态机自己的名字Reset,第二个参数为所属状态机的名字,表明Reset是状态机RecoveryMachine的一个状态。

有子状态情况下的状态定义:

struct Start;

struct Started : boost::statechart::state<Started, RecoveryMachine, Start>, NamedState {
};

状态Started也是状态机RecoveryMachine的一个状态,模板参数中多了一个参数Start,它是状态Started的默认初始子状态,其定义如下:

struct Start : boost::statechart::state<Start, Started>, NamedState {
};

上面定义的状态Start是状态Started的子状态。第一个模板参数是自己的名字,第二个模板参数是该子状态所属父状态的名字。

综上所述,一个状态,要么属于一个状态机,要么属于一个状态,成为该状态的子状态。其定义的模板参数是自己,第二个模板参数是拥有者,第三个模板参数是它的起始子状态。

1.2 事件

状态能够接收并处理事件。事件可以改变状态,促使状态发生转移。在boost库的statechart状态机中定义事件的方式如下所示:

struct QueryState : boost::statechart::event<QueryState> {
}; 

QueryState为一个事件,需要继承boost::statechart::event类,模板参数为自己的名字。

 

1.2.1状态响应事件

在一个状态内部,需要定义状态机处于当前状态时,可以接受的事件以及如何处理这些事件的方法:

#define TrivialEvent(T) struct T : boost::statechart::event< T > { \
    T() : boost::statechart::event< T >() {}               \
    void print(std::ostream *out) const {               \
      *out << #T;                           \
    }                                   \
  };
  TrivialEvent(Initialize)
  TrivialEvent(Load)
  TrivialEvent(NullEvt)

struct Initial : boost::statechart::state< Initial, RecoveryMachine >, NamedState {
  explicit Initial(my_context ctx);
  void exit();

  typedef boost::mpl::list <
boost::statechart::transition< Initialize, Reset >,
boost::statechart::custom_reaction< Load >,
boost::statechart::custom_reaction< NullEvt >,
boost::statechart::transition< boost::statechart::event_base, Crashed >
> reactions;

  boost::statechart::result react(const Load&);
  boost::statechart::result react(const MNotifyRec&);
  boost::statechart::result react(const MInfoRec&);
  boost::statechart::result react(const MLogRec&);
  boost::statechart::result react(const boost::statechart::event_base&) {
return discard_event();
  }
};

1.2.2 可处理的事件及处理对应事件的方法

上述代码列出了状态RecoveryMachine/Initial可以处理的事件列表和处理对应事件的方法:

1) 通过boost::mpl::list定义该状态可以处理多个事件类型。在本例中可以处理InitializeLoadNullEvtevent_base事件。

2)简单事件处理

boost::statechart::transition<Initialize, Reset>

定义了状态Initial接收到事件Initialize后,无条件直接跳转到Reset状态;

3) 用户自定义事件处理: 当接收到事件后,需要根据一些条件来决定状态如何转移,这个逻辑需要用户自己定义实现

boost::statechart::custom_reaction<Load>

custom_reaction定义了一个用户自定义的事件处理方法,必须有一个react()的处理函数处理对应该事件。状态转移的逻辑需要用户自己在react函数里实现:

boost::statechart::result react(const Load&);
4) NullEvt事件用户自定义处理,但是没有实现react()函数来处理,最终事件匹配了boost::statechart::event_base事件,直接调用函数discard_event把事件丢弃掉。

1.3 statechart示例

1. boost::statechart示例代码:

  1 // Example program
  2 #include <iostream>
  3 #include <string>
  4 #include <boost/statechart/custom_reaction.hpp>
  5 #include <boost/statechart/event.hpp>
  6 #include <boost/statechart/simple_state.hpp>
  7 #include <boost/statechart/state.hpp>
  8 #include <boost/statechart/state_machine.hpp>
  9 #include <boost/statechart/transition.hpp>
 10 #include <boost/statechart/event_base.hpp>
 11 
 12 #define TrivialEvent(T) struct T : boost::statechart::event< T > { \
 13     T() : boost::statechart::event< T >() {}               \
 14     void print(std::ostream *out) const {               \
 15       *out << #T;                           \
 16     }                                   \
 17   };
 18 
 19 TrivialEvent(Initialize)
 20 TrivialEvent(Load)
 21 TrivialEvent(NullEvt)
 22 TrivialEvent(GoClean)
 23 
 24 struct MInfoRec : boost::statechart::event< MInfoRec> 
 25 {
 26   std::string name; 
 27   MInfoRec(std::string name): name(name){
 28   }
 29   
 30   void print() {
 31     std::cout<<"MInfoRec: "<<name<<"\n";
 32   }
 33 };
 34 
 35 struct MLogRec : boost::statechart::event<MLogRec> 
 36 {
 37   std::string name; 
 38   MLogRec(std::string name): name(name) {
 39   }
 40     
 41   void print() {
 42       std::cout<<"MLogRec: "<<name<<"\n";
 43   }
 44 };
 45 
 46 struct MNotifyRec : boost::statechart::event<MNotifyRec> 
 47 {
 48   std::string name; 
 49   MNotifyRec(std::string name): name(name){    
 50   }
 51   
 52   void print() {
 53       std::cout<<"MNotifyRec: "<<name<<"\n";
 54   }
 55 };
 56 
 57 struct Initial; 
 58 struct RecoveryMachine : boost::statechart::state_machine< RecoveryMachine, Initial> {}; 
 59 
 60 struct Reset;
 61 
 62 struct Crashed : boost::statechart::state<Crashed, RecoveryMachine> 
 63 {
 64   explicit Crashed(my_context ctx) : my_base(ctx) {
 65     std::cout << "Hello, Crashed!\n";
 66   }
 67 };
 68     
 69 struct Initial : boost::statechart::state< Initial, RecoveryMachine> 
 70 {
 71   typedef boost::mpl::list< 
 72   boost::statechart::transition<Initialize, Reset>,
 73   boost::statechart::custom_reaction<Load>,
 74   boost::statechart::custom_reaction<NullEvt>,
 75   boost::statechart::transition<boost::statechart::event_base, Crashed>> reactions;
 76   
 77   explicit Initial(my_context ctx) : my_base(ctx) {
 78     std::cout << "Hello, Initial!\n";
 79   } 
 80   
 81   boost::statechart::result react(const Load& l) {
 82     return transit<Reset>();
 83   }
 84   
 85   boost::statechart::result react(const MNotifyRec& notify) {
 86     std::cout<<"Initial::react::MLogRec!\n"; 
 87     return discard_event();
 88   } 
 89 
 90   boost::statechart::result react(const MInfoRec& i) {
 91     std::cout<<"Initial::react::MNotifiyRec!\n";
 92 
 93     return discard_event();
 94   }
 95 
 96   boost::statechart::result react(const MLogRec& log) {
 97     std::cout<<"Initial::react::MLogRec!\n";
 98 
 99     return discard_event();
100   }
101     
102   boost::statechart::result react(const boost::statechart::event_base&) {
103     std::cout << "Initial event_base processed!\n";
104     return discard_event();
105   }
106   
107   void exit() { 
108     std::cout << "Bye, Initial!\n";
109   } 
110 };
111 
112 struct Reset : boost::statechart::state<Reset, RecoveryMachine> 
113 {
114   explicit Reset(my_context ctx) : my_base(ctx) {
115     std::cout << "Hello, Reset!\n";
116   } 
117   
118   void exit() { 
119     std::cout << "Bye, Reset!\n";
120   }
121 };
122 
123 int main(int argc, char *argv[])
124 {
125   RecoveryMachine machine;
126   
127   machine.initiate();
128   
129   // machine.process_event(NullEvt());                        //语句1
130   
131   //machine.process_event(GoClean());                        //语句2
132   
133   //machine.process_event(MNotifyRec("notify record"));      //语句3
134   
135   return 0;
136 }

 上面的示例与PG中对于Initial状态的处理类似,下面我们来看一下分别执行上述语句时的打印情况:

单独执行语句1:

单独执行语句2:

单独执行语句3:

参考资料

1. ceph peering机制再研究(2)

原文地址:https://www.cnblogs.com/sunbines/p/15720863.html