`

C++实现简单有限自动状态机

 
阅读更多

使用示例如下:

#include <stdio.h>
#include <unistd.h>
#include "simple_server.hpp"

using namespace SimpleServerFrame;

extern "C" {

StateFSM fsm;

enum TestState{
	s_INIT = 0,
	s_STATE_1 = 1,
	s_STATE_2 = 2,
	s_END = 3,
	s_ERR = 4,
};

enum TestEvent{
	e_EVENT_1 = 100,
	e_EVENT_2 = 101,
	e_EVENT_3 = 102,
	e_EVENT_NOT_EXIST = 103,
};

enum TestAction{
	a_ACTION_1 = 200,
	a_ACTION_2 = 201,
	a_ACTION_3 = 202,

	a_ACTION_END = 203,
	a_ACTION_ERROR = 204,
};

class Test:public IFsmCallback{
public:
	int FsmCallback(int actionID){
		switch(actionID){
		case a_ACTION_1:
			printf("s_INIT -> s_STATE_1\n");
			fsm.PushEvent(e_EVENT_2);
			break;
		case a_ACTION_2:
			printf("s_INIT -> s_STATE_2\n");
			break;
		case a_ACTION_3:
			printf("s_STATE_1 -> s_STATE_2\n");
			fsm.PushEvent(e_EVENT_3);
			break;
		case a_ACTION_END:
			printf("s_STATE_2 -> s_END\n");
			break;
		case a_ACTION_ERROR:
			printf("s_STATE_2 -> s_STATE_1 not allowed!\n");
			break;
		default:
			printf("invalid action id\n");
			break;
		}
		return 0;
	}
};

// one time
int init()
{
	// ... 
	fsm.AddFsmConfig(s_INIT, e_EVENT_1, s_STATE_1, a_ACTION_1);
	fsm.AddFsmConfig(s_INIT, e_EVENT_2, s_STATE_2, a_ACTION_2);

	fsm.AddFsmConfig(s_STATE_1, e_EVENT_2, s_STATE_2, a_ACTION_3);
	fsm.AddFsmConfig(s_STATE_2, e_EVENT_1, s_ERR, a_ACTION_ERROR);

	fsm.AddFsmConfig(s_STATE_2, e_EVENT_3, s_END, a_ACTION_END);
}

// each request
sResponse doJob(sRequest req)
{
	Test *tt = new Test();
	fsm.StartFsm(s_INIT, tt);
	fsm.RunFsm(e_EVENT_1, tt);

	sleep(1);

	sResponse res;
	res.iResId = req.iReqId;
	return res;
}

}

FSM源码如下:

#ifndef __STATE_FSM_HPP__
#define __STATE_FSM_HPP__

#include <vector>
#include <map>
#include <queue>

namespace SimpleServerFrame{

using std::queue;
using std::vector;
using std::map;

typedef struct _fsmTransition{
	int eventID;
	int nextState;
	int actionID;
}fsmTransition;

typedef struct _fsmState{
	vector<fsmTransition> vecTransition;
}fsmState;

class IFsmCallback{
public:
	virtual int FsmCallback(int actionID) = 0;
	int FsmGetCurState(){
		return _curState;
	}
	void FsmSetCurState(int curState){
		_curState = curState;
	}
private:
	int _curState;
};

class StateFSM{
public:
	StateFSM();
	virtual ~StateFSM();

	int StartFsm(int stateID, IFsmCallback *fsmobj);
	int AddFsmConfig(int curState, int eventID, int nextState, int actionID);
	int RunFsm(int eventID, IFsmCallback *fsmobj);

	int PushEvent(int eventID);

private:
	int doFsmEvent(int eventID, IFsmCallback *fsmobj);
	int getActionID(int curState, int eventID, int &nextState, int &actionID);
private:
	map<int, fsmState> mapState;
	queue<int> queueEvent;
};

}

#endif

 

#include "state_fsm.hpp"

using namespace SimpleServerFrame;
using std::pair;

StateFSM::StateFSM()
{
	mapState.clear();
}

StateFSM::~StateFSM()
{

}

int StateFSM::StartFsm(int stateID, IFsmCallback *fsmobj)
{
	map<int, fsmState>::iterator stateIter;
	stateIter = mapState.find(stateID);
	if(stateIter != mapState.end())
	{
		fsmState state = stateIter->second;
		if(state.vecTransition.size() == 0){
			return -2; // only one state
		}
	}
	else{
		return -1; // no such state
	}

	fsmobj->FsmSetCurState(stateID);
}

int StateFSM::AddFsmConfig(int curState, int eventID, int nextState, int actionID)
{
	fsmTransition transition;
	transition.eventID = eventID;
	transition.nextState = nextState;
	transition.actionID = actionID;

	map<int, fsmState>::iterator stateIter;
	stateIter = mapState.find(curState);
	if(stateIter != mapState.end()) {
		stateIter->second.vecTransition.push_back(transition);
	}
	else{
		fsmState state;
		state.vecTransition.push_back(transition);
		mapState.insert ( pair <int, fsmState>  ( curState, state ) );
	}
	for(stateIter = mapState.begin(); stateIter!= mapState.end(); stateIter ++){
		fsmState state = stateIter->second;
		for(int i = 0 ; i < state.vecTransition.size();i ++){
			transition = state.vecTransition[i];
		}
	}

}

int StateFSM::PushEvent(int eventID)
{
	queueEvent.push(eventID);
}

int StateFSM::doFsmEvent(int eventID, IFsmCallback *fsmobj)
{
	int curState = fsmobj->FsmGetCurState();

	int actionID;
	int nextState;
	int iRet = getActionID(curState, eventID, nextState, actionID);
	if(iRet == 0){
		fsmobj->FsmSetCurState(nextState);
		fsmobj->FsmCallback(actionID);
	}
	return 0;
}

int StateFSM::RunFsm(int eventID, IFsmCallback *fsmobj)
{
	doFsmEvent(eventID, fsmobj);
	while(!queueEvent.empty()){
		int eventID = queueEvent.front();
		queueEvent.pop();
		doFsmEvent(eventID, fsmobj);
	}
	return 0;
}

int StateFSM::getActionID(int curState, int eventID, int &nextState, int &actionID)
{
	map<int, fsmState>::iterator stateIter;
	stateIter = mapState.find(curState);
	if(stateIter != mapState.end()) {
		fsmState state = stateIter->second;
		vector<fsmTransition>::iterator traniter;
		for ( traniter = state.vecTransition.begin() ; traniter != state.vecTransition.end() ; traniter++ )
		{
			fsmTransition transition = *traniter;
			if(transition.eventID == eventID){
				nextState = transition.nextState;
				actionID = transition.actionID;
				return 0;
			}
		}
		return -2; //curstate has no such event
	}else{
		return -1; //no such state
	}
}

 

分享到:
评论

相关推荐

    Visual C++程序开发范例宝典(光盘) 第八部分

    Visual C++程序开发范例宝典配套光盘,因大小受限,所以分成8部分上传,必须全部下载才能正常解压! 第1章 窗体与界面设计 1.1 菜单应用实例 实例001 在系统菜单中添加菜单项 实例002 带图标的程序菜单 实例003...

    C++MFC教程

    下面简单讲述一下这种方法的实现方法: 代码如下 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //{{AFX_MSG_MAP(CMainFrame) ON_WM_CREATE() //}}AFX_MSG_MAP ON_COMMAND(ID_FONT_DROPDOWN, DoNothing) END_...

    Visual C++程序开发范例宝典(PDF扫描版).part3

     cc实例115 彩票抽奖机   3.12 OpenGL程序设计   cc实例116 制作OpenGL动画   cc实例117 利用OpenGL绘制立体模型   cc实例118 利用OpenGL绘制NURBS曲线  第4章 多媒体技术   4.1 动画   cc实例...

    C++Builder精彩编程实例集锦的源代码(1,2,3部分).rar

    C++Builder精彩编程实例集锦的源代码(1,2,3部分): 第一部分 界面设计 实例001 如何实现程序闪屏效果 实例002 如何实现程序窗口闪烁 实例003 如何制作吸附窗口程序 实例004 如何制作透明程序窗口 实例005 如何...

    vc++ 开发实例源码包

    C#源码,实现简单游览器。 RangeScan扫描器源代码 ip地址扫描,发送邮箱。 ResizableLib 测试开源界面库Resizable。 RsPicture 自定义了一个图片库,然后引用测试。 SimplePlayer 简单的媒体播放源码。 Skin_...

    Postgres扩展和服务,可实现自动故障转移和高可用性-C/C++开发

    pg_auto_failover pg_auto_failover是PostgreSQL扩展和服务,用于监视和管理Postgres集群的自动故障转移...监视节点跟踪数据节点的运行状况,并实现故障转移状态机。 在PostgreSQL节点上,pg_autoctl程序与Post一起运行

    Visual C++ 程序开发范例宝典 源码 光盘 part2

    cc实例161 判断文件是否被改动 第6章 操作系统与Windows相关程序 6.1 启动相关设置 cc实例 162 进入WindowscXP前发出警告 cc实例163 实现关机.c重启计算机 cc实例164 将程序设置成为开机自动执行的程序 ...

    Visual C++程序开发范例宝典(PDF扫描版).part2

     cc实例115 彩票抽奖机   3.12 OpenGL程序设计   cc实例116 制作OpenGL动画   cc实例117 利用OpenGL绘制立体模型   cc实例118 利用OpenGL绘制NURBS曲线  第4章 多媒体技术   4.1 动画   cc实例...

    path-planning:使用C ++实现的路径规划器,可使用来自传感器融合,本地化的数据并生成传递给控制器​​的航点来在高速公路中行驶

    CarND路径规划项目 无人驾驶汽车工程师纳米学位课程 ... 第一个实现简单明了。 它允许汽车以我所谓的手动编码方式行驶。 第二种实施依赖于成本/轨迹; 它更具说服力,但更难实施,并且在该项目中并不一定效率更高。

    基于Qt实现的简易图灵机系统(输入初始状态、终止状态和状态转移函数,判断给定的输入带是否能被图灵机接受).zip

    2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。...

    C++Builder精彩编程实例集锦的源代码后3部分.rar

    实例044 如何显示简单关于对话框 实例045 如何在程序中增加热键 实例046 如何在程序中自定义消息 实例047 如何在程序中自定义系统菜单 实例048 如何在执行程序间进行数据通信 实例049 如何使用OLE技术启动画图 ...

    vc++ 应用源码包_6

    C#源码,实现简单游览器。 RangeScan扫描器源代码 ip地址扫描,发送邮箱。 ResizableLib 测试开源界面库Resizable。 RsPicture 自定义了一个图片库,然后引用测试。 SimplePlayer 简单的媒体播放源码。 Skin_...

    C++Builder精彩编程实例集锦的源代码前3部分.rar

    实例044 如何显示简单关于对话框 实例045 如何在程序中增加热键 实例046 如何在程序中自定义消息 实例047 如何在程序中自定义系统菜单 实例048 如何在执行程序间进行数据通信 实例049 如何使用OLE技术启动画图 ...

    Visual C++程序开发范例宝典(光盘) 第四部分

    Visual C++程序开发范例宝典配套光盘,因大小受限,所以分成8部分上传,必须全部下载才能正常解压! 第1章 窗体与界面设计 1.1 菜单应用实例 实例001 在系统菜单中添加菜单项 实例002 带图标的程序菜单 实例003...

    visual C++_Turbo C串口通信编程实践

    4.2.4 通信错误与通信设备状态 4.2.5 串行通信事件 4.3 Windows API串行通信函数 4.4 Win32 API串口通信编程的一般流程和特殊实例 4.4.1 Win32 API串口通信编程的一般流程 4.4.2 用查询方式读串口 4.4.3...

    vc++ 应用源码包_1

    C#源码,实现简单游览器。 RangeScan扫描器源代码 ip地址扫描,发送邮箱。 ResizableLib 测试开源界面库Resizable。 RsPicture 自定义了一个图片库,然后引用测试。 SimplePlayer 简单的媒体播放源码。 Skin_...

    vc++ 应用源码包_2

    C#源码,实现简单游览器。 RangeScan扫描器源代码 ip地址扫描,发送邮箱。 ResizableLib 测试开源界面库Resizable。 RsPicture 自定义了一个图片库,然后引用测试。 SimplePlayer 简单的媒体播放源码。 Skin_...

    vc++ 应用源码包_5

    C#源码,实现简单游览器。 RangeScan扫描器源代码 ip地址扫描,发送邮箱。 ResizableLib 测试开源界面库Resizable。 RsPicture 自定义了一个图片库,然后引用测试。 SimplePlayer 简单的媒体播放源码。 Skin_...

    vc++ 应用源码包_3

    C#源码,实现简单游览器。 RangeScan扫描器源代码 ip地址扫描,发送邮箱。 ResizableLib 测试开源界面库Resizable。 RsPicture 自定义了一个图片库,然后引用测试。 SimplePlayer 简单的媒体播放源码。 Skin_...

Global site tag (gtag.js) - Google Analytics