1. 程式人生 > >【原創】技術系列之 狀態機(二)

【原創】技術系列之 狀態機(二)

與常規狀態機相比,它的FSM_STATE結構沒有default_func,多了 FSM_STATE_ID parent; FSM_STATE_ID default_child;兩個結構。狀態機初始化的時候可以指定預設狀態,為了防止指定的狀態非葉結點,增加fsm_init方法。該狀態機的事件處理演算法簡單描述如下:(1)首先在當前狀態以及其祖先狀態的狀態事件表中搜索匹配事件,如果搜尋到,儲存操作以及目的狀態標識;(2)在old棧中儲存當前狀態到根節點的路徑,在new棧中儲存目的狀態到根節點的路徑;(3)將old棧中的頂層元素依次與new棧的頂層元素匹配,如果匹配則都出棧,不匹配,停止;(4)當前的old棧中節點即為該事件導致的退出狀態,從棧低掃描到棧頂,依次執行exit_func;(5)執行以前儲存的操作;(6)掃描new棧,從棧頂到棧低依次執行enter_func;(7)最後檢測目的狀態是否是葉節點狀態,否,則依次進入default_child節點,並執行enter_func。模組實現程式碼如下: #define SINGLE_STATE_MAX_EVENT 10
#define STATE_TREE_DEPTH 
10
typedef  
int FSM_EVENT_ID;
typedef struct event_param_st
{
    FSM_EVENT_ID id;
    union
{
        
int i;
    }
data;
}
FSM_EVENT;
typedef  
int FSM_STATE_ID;
typedef 
void (*FSM_FUNC)(FSM_EVENT *);
typedef struct state_event_st
{
    FSM_FUNC func;
    FSM_EVENT_ID event;
    FSM_STATE_ID state;
}
FSM_STATE_EVENT;
typedef struct state_st
{
    FSM_STATE_ID id;
    
char*name;
    FSM_STATE_ID parent;
    FSM_STATE_ID default_child;
    FSM_FUNC enter_func;
    FSM_FUNC exit_func;
    FSM_STATE_EVENT event_table[SINGLE_STATE_MAX_EVENT]; 
}
FSM_STATE;
typedef FSM_STATE STATE_TABLE[];
typedef FSM_STATE 
* PTR_STATE_TABLE;

#define END_EVENT_ID 
-1
#define END_STATE_ID 
-1
#define BEGIN_FSM_STATE_TABLE(state_stable) 
static STATE_TABLE state_stable={
#define BEGIN_STATE(id,name,parent,default_child,enter_func,exit_func) 
{id,name,parent,default_child,enter_func,exit_func,{
#define STATE_EVENT_ITEM(func,event,state) 
{func,event,state},
#define END_STATE(id) 
{NULL,END_EVENT_ID,END_STATE_ID}}
}
,
#define END_FSM_STATE_TABLE(state_stable) 
{END_STATE_ID,NULL,END_STATE_ID,END_STATE_ID,NULL,NULL,NULL}}
;

typedef struct fsm_st
{
    FSM_STATE_ID state_id;
    FSM_FUNC default_func;
    PTR_STATE_TABLE state_tables;
}
FSM;

void fsm_init(FSM &fsm)
{
    FSM_STATE 
*state=&(fsm.state_tables[fsm.state_id]);
    
while(state->default_child!=END_STATE_ID)
    
{
        state
=&(fsm.state_tables[state->default_child]);
        
if(state->enter_func)
            state
->enter_func(NULL);
    }

    fsm.state_id
=state->id;
}

void fsm_do_event(FSM &fsm, FSM_EVENT &event)
{
    FSM_STATE 
*state;
    FSM_STATE_ID state_id,old_state_id,new_state_id;
    FSM_STATE_ID oldStack[STATE_TREE_DEPTH],newStack[STATE_TREE_DEPTH];
    
int old_cur=0,new_cur=0;
    
    bool isMatch
=false;
    FSM_FUNC match_func
=NULL;
    
int i=0;
    state_id
=old_state_id=fsm.state_id;
    
do
    
{
        i
=0;
        state
=&(fsm.state_tables[state_id]);
        
while(state->event_table[i].event!=END_EVENT_ID)
        
{
            
if(state->event_table[i].event==event.id)
            
{
                isMatch
=true;
                match_func
=state->event_table[i].func;
                new_state_id
=state->event_table[i].state;
                
break;
            }

            i
++;
        }

        
if(isMatch==false)
            state_id
=state->parent;
        
else
            
break;
    }
while(state->parent!=END_STATE_ID);
    
if(isMatch==false)
    
{
        
if(fsm.default_func)
            fsm.default_func(
&event);
        
return;
    }

    
if(new_state_id==old_state_id)
    
{
        
if(match_func)
            match_func(
&event);
        
return;
    }

    state_id
=old_state_id;
    
do
    
{
        oldStack[old_cur
++]=state_id;
        state
=&(fsm.state_tables[state_id]);
        state_id
=state->parent;
    }
while(state->parent!=END_STATE_ID);
    state_id
=new_state_id;
    
do
    
{
        newStack[new_cur
++]=state_id;
        state
=&(fsm.state_tables[state_id]);
        state_id
=state->parent;
    }
while(state->parent!=END_STATE_ID);
    
while(oldStack[old_cur-1]==newStack[new_cur-1])
    
{
        old_cur
--;
        new_cur
--;
    }

    
for(i=0;i<old_cur;i++)
    
{
        
if(fsm.state_tables[oldStack[i]].exit_func)
            fsm.state_tables[oldStack[i]].exit_func(
&event);
    }

    
if(match_func)
        match_func(
&event);
    
for(i=new_cur;i>0;i--)
    
{
        
if(fsm.state_tables[newStack[i-1]].enter_func)
            fsm.state_tables[newStack[i
-1]].enter_func(&event);
    }

    state
=&(fsm.state_tables[new_state_id]);
    
while(state->default_child!=END_STATE_ID)
    
{
        state
=&(fsm.state_tables[state->default_child]);
        
if(state->enter_func)
            state
->enter_func(&event);
    }

    fsm.state_id
=state->id;
}
使用舉例,僅僅列舉一個狀態表和簡單的狀態機初始化,狀態和事件應該為enum,當前使用數字,僅為了舉例,操作的實現不在寫出。 BEGIN_FSM_STATE_TABLE(my_state_table)
    BEGIN_STATE(
0,"first",END_STATE_ID,2,enter_fsm,exit_fsm)
        STATE_EVENT_ITEM(func_fsm,
1,1)
        STATE_EVENT_ITEM(func_fsm,
2,2)
    END_STATE(
0)
    

相關推薦

原創技術系列 狀態

與常規狀態機相比,它的FSM_STATE結構沒有default_func,多了 FSM_STATE_ID parent; FSM_STATE_ID default_child;兩個結構。狀態機初始化的時候可以指定預設狀態,為了防止指定的狀態非葉結點,增加fsm_init方法。該狀態機的事件處理演算

原創技術系列 狀態

作者:CppExplore 網址:http://www.cppblog.com/CppExplore/一、狀態機描述狀態機理論最初的發展在數位電路設計領域。在數位電路方面,根據輸出是否與輸入訊號有關,狀態機可以劃分為Mealy型和Moore型狀態機;根據輸出是否與輸入訊號同步,狀態機可以劃分為非同步和

原創技術系列 記憶體管理

作者:CppExplore 地址:http://www.cppblog.com/CppExplore/(2)boost::pool系列。boost的記憶體池最低層是simple_segregated_storage,類似於Loki中的chunk,在其中申請釋放block(boost中把block稱為c

原創技術系列 執行緒

作者:CppExplore 網址:http://www.cppblog.com/CppExplore/廢話不多說,詳細介紹使用執行緒的優點好處請參考baidu、google。一、執行緒使用場景。使用執行緒的方式大致有兩種:(1)流水線方式。根據業務特點,將一個流程的處理分割成多個執行緒,形成流水線的處

原創Linux虛擬化KVM-Qemu分析ARMv8虛擬化

# 背景 - `Read the fucking source code!` --By 魯迅 - `A picture is worth a thousand words.` --By 高爾基 說明: 1. KVM版本:5.9.1 2. QEMU版本:5.0.0 3. 工具:Source Insight

NIFI Apache NiFI ExecuteScript處理 NIFI Apache NiFI ExecuteScript處理

  本例介紹NiFI ExecuteScript處理器的使用,使用的指令碼引擎ECMScript   接上一篇【NIFI】 Apache NiFI 之 ExecuteScript處理(一) ExecuteScript使用   1、動態屬性     其中一個功能是動態屬性的概念,也稱為使用者定義屬性。這

原創從原始碼剖析IO流檔案流--轉載請註明出處

一、FileInputStream 在FileInputStream中,首先我們需要進行關注的方法,就是read()方法,下面可以來看一下read()方法的原始碼: public int read() throws IOException { return read0()

技術系列 記憶體管理

2、定長記憶體池。典型的實現有LOKI、BOOST。特點是為不同型別的資料結構分別建立記憶體池,需要記憶體的時候從相應的記憶體池中申請記憶體,優點是可以在使用完畢立即把記憶體歸還池中,可以更為細粒度的控制記憶體塊。    與變長的相比,這種型別的記憶體池更加通用,另一方面對於

技術系列 網路模型

作者:CppExplore 網址:http://www.cppblog.com/CppExplore/本章主要列舉伺服器程式的各種網路模型,示例程式以及效能對比後面再寫。一、分類依據。伺服器的網路模型分類主要依據以下幾點(1)是否阻塞方式處理請求,是否多路複用,使用哪種多路複

技術系列 執行緒

為了後面寫的《網路模型(二)》,多寫一篇關於執行緒的。執行緒使用涉及的主要資料結構以及應用框架可以參考http://www.cppblog.com/CppExplore/archive/2008/01/15/41175.html。本文的主要目的是給出linux下實用的執行緒訊

Java基本型別整數型別

        Java的整數型別,即沒有小數部分的資料,分別有byte、short、int、long,每種型別都有自己的取值範圍,超出就會報異常。         Java的整數型別有四種表示方式:

原創Linux PCI驅動框架分析

# 背 景 - `Read the fucking source code!` --By 魯迅 - `A picture is worth a thousand words.` --By 高爾基 說明: 1. Kernel版本:4.14 2. ARM64處理器 3. 使用工具:Source Insight

原創Linux虛擬化KVM-Qemu分析KVM原始碼1

# 背景 - `Read the fucking source code!` --By 魯迅 - `A picture is worth a thousand words.` --By 高爾基 說明: 1. KVM版本:5.9.1 2. QEMU版本:5.0.0 3. 工具:Source Insight

原創Linux虛擬化KVM-Qemu分析CPU虛擬化2

# 背景 - `Read the fucking source code!` --By 魯迅 - `A picture is worth a thousand words.` --By 高爾基 說明: 1. KVM版本:5.9.1 2. QEMU版本:5.0.0 3. 工具:Source Insight

原創Linux虛擬化KVM-Qemu分析記憶體虛擬化

# 背景 - `Read the fucking source code!` --By 魯迅 - `A picture is worth a thousand words.` --By 高爾基 說明: 1. KVM版本:5.9.1 2. QEMU版本:5.0.0 3. 工具:Source Insight

原創Linux虛擬化KVM-Qemu分析中斷虛擬化

# 背景 - `Read the fucking source code!` --By 魯迅 - `A picture is worth a thousand words.` --By 高爾基 說明: 1. KVM版本:5.9.1 2. QEMU版本:5.0.0 3. 工具:Source Insight

原創Linux虛擬化KVM-Qemu分析timer虛擬化

# 背景 - `Read the fucking source code!` --By 魯迅 - `A picture is worth a thousand words.` --By 高爾基 說明: 1. KVM版本:5.9.1 2. QEMU版本:5.0.0 3. 工具:Source Insight

原創Linux虛擬化KVM-Qemu分析virtio初探

# 背景 - `Read the fucking source code!` --By 魯迅 - `A picture is worth a thousand words.` --By 高爾基 說明: 1. KVM版本:5.9.1 2. QEMU版本:5.0.0 3. 工具:Source Insight

原創Linux虛擬化KVM-Qemu分析virtio裝置

# 背景 - `Read the fucking source code!` --By 魯迅 - `A picture is worth a thousand words.` --By 高爾基 說明: 1. KVM版本:5.9.1 2. QEMU版本:5.0.0 3. 工具:Source Insight

原創Linux虛擬化KVM-Qemu分析virtio驅動

# 背景 - `Read the fucking source code!` --By 魯迅 - `A picture is worth a thousand words.` --By 高爾基 說明: 1. KVM版本:5.9.1 2. QEMU版本:5.0.0 3. 工具:Source Insight