欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

有限状态机FSM(C++)

程序员文章站 2024-03-19 18:00:58
...

最近开发一个系统,要用到比较多的状态机,若像是以前那样,每个状态机都分开实现,过于麻烦。故简单设计了个简单的模型
有限状态机FSM(C++)
上图所示是一个简单的状态机示意图。按照个人理解状态机的一般处理都是,在主循环中检查事件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++