有限状态机FSM(C++)
程序员文章站
2024-03-19 18:00:58
...
最近开发一个系统,要用到比较多的状态机,若像是以前那样,每个状态机都分开实现,过于麻烦。故简单设计了个简单的模型
上图所示是一个简单的状态机示意图。按照个人理解状态机的一般处理都是,在主循环中检查事件Event,若事件发生则进行动作Action,若没发生则执行状态处理StateAction。动作Action完成后一般会进行状态的迁移。所以按照面向对象的思想来说,可将其分为以下三个类:
- Fsm
- FsmState
- FsmEvent
1.1 Fsm
负责整个状态机的扫描
class Fsm
{
public:
public:
Fsm();
int register_state(FsmState *state);
void scan();
inline FsmState *get_cur_state() const { return cur_state; }
inline void start() { cur_state = *state_tab.begin(); }
private:
FsmState *cur_state;
vector<FsmState *> state_tab;
};
1.2 FsmState
检查发生的事件,并调用事件的动作。已经执行状态自身的处理
class FsmState
{
public:
FsmState(int id = 0);
int register_event(FsmEvent *ev);
FsmState* scan();
virtual int action() = 0;
int reset();
inline int get_id() const { return id_; }
protected:
FsmEvent *select_active_event();
int id_;
list<FsmEvent *> event_list;
};
1.3 FsmEvent
定义事件的动作,事件应该有优先级,并且明确事件发生的前一状态和后续状态。
class FsmEvent
{
public:
FsmEvent(FsmState *from, FsmState *to, int priority);
int trigger(Fsm &fsm,void *param);
virtual int action(FsmState* cur_state) = 0;
inline int get_prio() const { return prio_; }
inline FsmState *get_req() const { return to_; }
inline bool is_active() const { return active_; }
inline void reset() { active_ = false; param_ = 0; }
protected:
int prio_;
FsmState *from_;
FsmState *to_;
bool active_;
void *param_;
};
1.4 各个类的实现如下
#include "fsm.h"
FsmEvent::FsmEvent(FsmState *from, FsmState *to, int prio)
:prio_(prio), from_(from), to_(to), active_(false), param_(0)
{
}
int FsmEvent::trigger(Fsm &fsm,void *param)
{
if (from_ != fsm.get_cur_state())
return -1;
param_ = param;
active_ = true;
return 0;
}
FsmState::FsmState(int id):id_(id)
{
event_list.clear();
}
int FsmState::register_event(FsmEvent *ev)
{
int prio = ev->get_prio();
if (event_list.size() == 0)
{
event_list.push_back(ev);
return 0;
}
list<FsmEvent*>::iterator pre = event_list.begin();
if (prio < (*pre)->get_prio())
{
event_list.push_front(ev);
return 0;
}
list<FsmEvent*>::iterator it = event_list.begin();
for (it++; it != event_list.end(); it++,pre++)
{
if (prio == (*it)->get_prio()
|| prio == (*pre)->get_prio())
return -1;
if (prio<(*it)->get_prio() && prio>(*pre)->get_prio())
{
event_list.insert(it, ev);
return 0;
}
}
event_list.push_back(ev);
return 0;
}
FsmEvent *FsmState::select_active_event()
{
for (list<FsmEvent*>::iterator it = event_list.begin(); it != event_list.end(); it++)
{
if ((*it)->is_active() == true)
{
return *it;
}
}
return 0;
}
FsmState* FsmState::scan()
{
FsmEvent *ev = select_active_event();
if (ev && !ev->action(this))
{
reset();
return ev->get_req();
}
else
action();
return 0;
}
int FsmState::reset()
{
for (list<FsmEvent*>::iterator it = event_list.begin(); it != event_list.end(); it++)
(*it)->reset();
return 0;
}
Fsm::Fsm()
{
state_tab.clear();
}
int Fsm::register_state(FsmState *state)
{
for (vector<FsmState *>::iterator it = state_tab.begin(); it != state_tab.end(); it++)
{
if (state->get_id() == (*it)->get_id())
return -1;
}
state_tab.push_back(state);
return 0;
}
void Fsm::scan()
{
if (cur_state)
{
FsmState *req = cur_state->scan();
if (req)
cur_state = req;
}
}
2. 使用
通过继承使用该简易模型
class TestEv1 :public FsmEvent
{
public:
TestEv1(FsmState *from, FsmState *to, int prio) :FsmEvent(from, to, prio) {}
int action(FsmState *cur)
{
std::cout << "TestEv1:" << prio_ << std::endl;
return 0;
}
};
class TestEv2 :public FsmEvent
{
public:
TestEv2(FsmState *from, FsmState *to, int prio) :FsmEvent(from, to, prio) {}
int action(FsmState *cur)
{
std::cout << "TestEv2:" << prio_ << std::endl;
return 0;
}
};
class TestBoot :public FsmState
{
public:
TestBoot() { id_ = 0; }
int action()
{
std::cout << "TestBoot:" << id_ << std::endl;
return 0;
}
};
class TestDisable :public FsmState
{
public:
TestDisable() { id_ = 1; }
int action()
{
std::cout << "TestDisable:" << id_ << std::endl;
return 0;
}
};
Fsm test_fsm;
TestDisable disable_state;
TestBoot boot_state;
TestEv1 ev10(&disable_state, &boot_state, 0);
TestEv1 ev11(&disable_state, &boot_state, 1);
TestEv1 ev12(&disable_state, &boot_state, 2);
disable_state.register_event(&ev11);
disable_state.register_event(&ev10);
disable_state.register_event(&ev12);
test_fsm.register_state(&disable_state);
TestEv2 ev21(&boot_state, &disable_state, 1);
TestEv2 ev22(&boot_state, &disable_state, 2);
boot_state.register_event(&ev21);
boot_state.register_event(&ev22);
test_fsm.register_state(&boot_state);
test_fsm.start();
int err = ev21.trigger(test_fsm, 0);
err = ev22.trigger(test_fsm, 0);
err = ev10.trigger(test_fsm, 0);
err = ev11.trigger(test_fsm, 0);
test_fsm.scan();
test_fsm.scan();
test_fsm.scan();
test_fsm.scan();
ev22.trigger(test_fsm, 0);
test_fsm.scan();
test_fsm.scan();
其他
都是自己瞎想的,若有不对,或者建议,还请各位大神不吝赐教。
上一篇: 移动自动化测试框架拓展
下一篇: C语言实现有限状态机