zoukankan      html  css  js  c++  java
  • 【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)

  • 相关阅读:
    BZOJ1050: [HAOI2006]旅行comf(并查集 最小生成树)
    洛谷P1762 偶数(找规律)
    抽象类的基本概念------abstract
    百度地图小图标没有显示的解决方案
    nfs:server 172.168.1.22 not responding,still trying问题解决方法 平台为RealARM 210平台
    大话分页(二)
    In App Purchases(IAP 应用程序內购买): 完全攻略
    快速修改数组的问题
    64位linux中使用inet_ntoa报错处理
    CDN和双线机房相比有何优势
  • 原文地址:https://www.cnblogs.com/sunbines/p/15720863.html
Copyright © 2011-2022 走看看