C语言 有限状态机
狀態存儲關于過去的信息,就是說:它反映從系統開始到現在時刻的輸入變化。轉移指示狀態變更,并且用必須滿足來確使轉移發生的條件來描述它。動作是在給定時刻要進行的活動的描述。有多種類型的動作: 進入動作(entry action):在進入狀態時進行 退出動作:在退出狀態時進行 輸入動作:依賴于當前狀態和輸入條件進行 轉移動作:在進行特定轉移時進行 下面展示最常見的表示:當前狀態(B)和條件(Y)的組合指示出下一個狀態(C)。完整的動作信息可以只使用腳注來增加。包括完整動作信息的FSM 定義可以使用狀態表。
除了建模這里介紹的反應系統之外,有限狀態自動機在很多不同領域中是重要的,包括電子工程、?語言學、計算機科學、哲學、生物學、數學和邏輯學。有限狀態機是在自動機理論和計算理論中研究的一類自動機。在計算機科學中,有限狀態機被廣泛用于建模應用行為、硬件電路系統設計、軟件工程,編譯器、網絡協議、和計算與語言的研究。 地位 在數字電路系統中,有限狀態機是一種十分重要的時序邏輯電路模塊 作用 它對數字系統的設計具有十分重要的作用。 有限狀態機是指輸出取決于過去輸入部分和當前輸入部分的時序邏輯電路。一般來說,除了輸入部分和輸出部分外,有限狀態機還含有一組具有“記憶”功能的寄存器,這些寄存器的功能是記憶有限狀態機的內部狀態,它們常被稱為狀態寄存器。在有限狀態機中,狀態寄存器的的下一個狀態不僅與輸入信號有關,而且還與該寄存器的當前狀態有關,因此有限狀態機又可以認為是組合邏輯和寄存器邏輯的一種組合。其中,寄存器邏輯的功能是存儲有限狀態機的內部狀態;而組合邏輯又可以分為次態邏輯和輸出邏輯兩部分,次態邏輯的功能是確定有限狀態機的下一個狀態,輸出邏輯的功能是確定有限狀態機的輸出。 分類 在實際的應用中,根據有限狀態機是否使用輸入信號,設計人員經常將其分為Moore型有限狀態機和Mealy型有限狀態機兩種類型。1Moore型有限狀態機其輸出信號僅與當前狀態有關,即可以把Moore型有限狀態的輸出看成是當前狀態的函數。2 Mealy型有限狀態機其輸出信號不僅與當前狀態有關,而且還與所有的輸入信號有關,即可以把Mealy型有限狀態機的輸出看成是當前狀態和所有輸入信號的函數。 編程 有限狀態機體現了兩點:首先是離散的,然后是有限的。 State: 狀態這個詞有些難以定義,狀態存儲關于過去的信息,就是說它反映從系統開始到現在時刻的輸入變化。 Actions & Transitions: 轉換指示狀態變更,并且用必須滿足來確使轉移發生的條件來描述它。動作是在給定時刻要進行的活動的描述。 Guards: 檢測器出現的原因是為了檢測是否滿足從一個狀態切換到另外一個狀態的條件。 Event: 事件,又見事件,籠統說來,對系統重要的某件事情被稱為事件。 恩,就這些了,有些迷惑么:),恩,我們來理清一下思路:先從事件說起,事件是有生命 的,它經歷: 1).被產生(被接受,等待被處理,一般放入事件隊列) 2).被分發(從事件隊列取出,分發到響應的狀態機處理) 3).死亡(當狀態機處理了該事件,它隨之死亡) 從一個狀態切換到另外一個狀態被稱為狀態轉換,而引起它的事件稱為觸發事件.(可以看到,不是所有的事件都會引起狀態的轉換). 提到狀態轉換,不能不提及檢測器(Guards),只有當檢測器的值為TRUE時候,才能啟動轉換 應用 常見的計算機就是使用有限狀態機作為計算模型的:對于內存的不同狀態,CPU通過讀取內存值進行計算,更新內存中的狀態。CPU還通過消息總線接受外部輸入設備(如鍵盤、鼠標)的指令,計算后更改內存中的狀態,計算結果輸出到外部顯示設備(如顯示器),以及持久化存儲在硬盤。 電腦游戲設計中也經常使用有限狀態機模型。以水果忍者游戲為例,游戲中水果的狀態是有限狀態,其運行軌跡是由模擬物理運動規律的計算公式運算而成的,一個香蕉拋起來后會按照拋物線運行,其每一幀位置變化都是一個狀態的改變,狀態改變通過計算公式來決定。當然作為游戲不會僅僅這么簡單,如果這么簡單就是動畫了,游戲還有復雜的人機交互事件,比如用手在屏幕上“切”了水果,水果感知到這個事件后,會按照程序邏輯進入爆炸狀態。
| 當前狀態 → 條件 ↓ | 狀態 A | 狀態 B | 狀態 C |
| 條件 X | … | … | … |
| 條件 Y | … | 狀態 C | … |
| 條件 Z | … | … | … |
1、狀態機的要素
狀態機可歸納為4個要素,即現態、條件、動作、次態。“現態”和“條件”是因,“動作”和“次態”是果。詳解如下:
①現態:是指當前所處的狀態。
②條件:又稱為“事件”。當一個條件被滿足,將會觸發一個動作,或者執行一次狀態的遷移。
③動作:條件滿足后執行的動作。動作執行完畢后,可以遷移到新的狀態,也可以仍舊保持原狀態。動作不是必需的,當條件滿足后,也可以不執行任何動作,直接遷移到新狀態。
④次態:條件滿足后要遷往的新狀態。“次態”是相對于“現態”而言的,“次態”一旦被激活,就轉變成新的“現態”了。
這里需要注意的兩個問題:
1、避免把某個“程序動作”當作是一種“狀態”來處理。那么如何區分“動作”和“狀態”?“動作”是不穩定的,即使沒有條件的觸發,“動作”一旦執行完畢就結束了;而“狀態”是相對穩定的,如果沒有外部條件的觸發,一個狀態會一直持續下去。
2、狀態劃分時漏掉一些狀態,導致跳轉邏輯不完整。
所以維護上述一張狀態表就非常必要,而且有意義了。從表中可以直觀看出那些狀態直接存在跳轉路徑,那些狀態直接不存在。如果不存在,就把對應的單元格置灰。每次寫代碼之前先把表格填寫好,并且對置灰的部分重點review,看看是否有“漏態”,然后才是寫代碼。QA拿到這張表格之后,寫測試用例也是手到擒來。
有限狀態機FSM
思想廣泛應用于硬件控制電路設計,也是軟件上常用的一種處理方法(軟件上稱為FMM--有限消息機)。它把復雜的控制邏輯分解成有限個穩定狀態,在每個狀態上判斷事件,變連續處理為離散數字處理,符合計算機的工作特點。同時,因為有限狀態機具有有限個狀態,所以可以在實際的工程上實現。但這并不意味著其只能進行有限次的處理,相反,有限狀態機是閉環系統,有限無窮,可以用有限的狀態,處理無窮的事務。 有限狀態機的工作原理如圖1所示,發生事件(event)后,根據當前狀態(cur_state),決定執行的動作(action),并設置下一個狀態號(nxt_state)。 ------------- | |-------->執行動作action 發生事件event ----->| cur_state | | |-------->設置下一狀態號nxt_state ------------- 當前狀態 圖1 有限狀態機工作原理 e0/a0 --->-- | | -------->---------- e0/a0 | | S0 |----- | -<------------ | e1/a1 | | e2/a2 V ---------- ---------- | S2 |-----<-----| S1 | ---------- e2/a2 ---------- 圖2 一個有限狀態機實例 -------------------------------------------- 當前狀態 s0 s1 s2 | 事件 -------------------------------------------- a0/s0 -- a0/s0 | e0 -------------------------------------------- a1/s1 -- -- | e1 -------------------------------------------- a2/s2 a2/s2 -- | e2 -------------------------------------------- 表1 圖2狀態機實例的二維表格表示(動作/下一狀態) 圖2為一個狀態機實例的狀態轉移圖,它的含義是: 在s0狀態,如果發生e0事件,那么就執行a0動作,并保持狀態不變; 如果發生e1事件,那么就執行a1動作,并將狀態轉移到s1態; 如果發生e2事件,那么就執行a2動作,并將狀態轉移到s2態; 在s1狀態,如果發生e2事件,那么就執行a2動作,并將狀態轉移到s2態; 在s2狀態,如果發生e0事件,那么就執行a0動作,并將狀態轉移到s0態; 有限狀態機不僅能夠用狀態轉移圖表示,還可以用二維的表格代表。一般將當前狀態號寫在橫行上,將事件寫在縱列上,如表1所示。其中“--”表示空(不執行動作,也不進行狀態轉移),“an/sn”表示執行動作an,同時將下一狀態設置為sn。表1和圖2表示 的含義是完全相同的。 觀察表1可知,狀態機可以用兩種方法實現:豎著寫(在狀態中判斷事件)和橫著寫(在事件中判斷狀態)。這兩種實現在本質上是完全等效的,但在實際操作中,效果卻截然 不同。豎著寫C代碼片段
cur_state = nxt_state; switch(cur_state){ //在當前狀態中判斷事件 case s0: //在s0狀態 if(e0_event){ //如果發生e0事件,那么就執行a0動作, 并保持狀態不變; 執行a0動作; //nxt_state = s0; //因為狀態號是自身,所以可以刪除此句 ,以提高運行速度。 } else if(e1_event){ //如果發生e1事件,那么就執行a1動作, 并將狀態轉移到s1態; 執行a1動作; nxt_state = s1; } else if(e2_event){ //如果發生e2事件,那么就執行a2動作, 并將狀態轉移到s2態; 執行a2動作; nxt_state = s2; } break; case s1: //在s1狀態 if(e2_event){ //如果發生e2事件,那么就執行a2動作, 并將狀態轉移到s2態; 執行a2動作; nxt_state = s2; } break; case s2: //在s2狀態 if(e0_event){ //如果發生e0事件,那么就執行a0動作, 并將狀態轉移到s0態; 執行a0動作; nxt_state = s0; } } 橫著寫(在事件中判斷狀態)C代碼片段 //e0事件發生時,執行的函數 void e0_event_function(int * nxt_state) { int cur_state; cur_state = *nxt_state; switch(cur_state){ case s0: //觀察表1,在e0事件發生時,s1處為空 case s2: 執行a0動作; *nxt_state = s0; } } //e1事件發生時,執行的函數 void e1_event_function(int * nxt_state) { int cur_state; cur_state = *nxt_state; switch(cur_state){ case s0: //觀察表1,在e1事件發生時,s1和s2處為 空 執行a1動作; *nxt_state = s1; } } //e2事件發生時,執行的函數 void e2_event_function(int * nxt_state) { int cur_state; cur_state = *nxt_state; switch(cur_state){ case s0: //觀察表1,在e2事件發生時,s2處為空 case s1: 執行a2動作; *nxt_state = s2; } }總結
- 上一篇: 亚信安全认证acse_构建中国云生态|华
- 下一篇: 共创世界CCW,是什么Scratch编程