The Principle of FSM and the Realization of GO

Keywords: Go


Finite-state machine (FSM) can also be called finite-state automata. It must be able to attach to something, and the state of the thing is limited, through some trigger events, will make its state transition. Therefore, the finite state machine (FSM) is a mathematical model describing these finite states, trigger events and transition behavior.

Finite State Machine Composition

The finite state machine has two essential characteristics, one is discrete, the other is finite. Based on these two points, the vast majority of things in the real world cannot be represented by finite state machines because of their complex states.

The elements of the finite state machine model describing things consist of the following elements:

  • State: The state of something, including the initial state and the state after all events have been triggered.
  • Event: Event that triggers a state change or remains in its original state
  • Action / Transition: The process of performing state transitions
  • Guard: Detects whether the conditions under which one state is to be converted to another are satisfied

application area

In addition to the mathematical model applications just introduced, finite state machines have important applications in many different fields, including electrical engineering, linguistics, computer science, philosophy, biology, mathematics and logic. Finite state machines belong to automata theory. As can be seen from the domain hierarchy of automata theory below, the more complex the outer concepts are.


Examples of Finite State Machines

Let's take the most classic fans around us for example. If the fan has four buttons, one, two and three, the shutdown button is responsible for closing the fan, that is, stopping the rotation of the fan; and the 1, 2 and 3 gears can make the fan open, and the speed of the fan rotation is different, the generated wind is also different.

At this time, we can judge the four states of the fan: power off, 1st gear, 2nd gear and 3rd gear. The press operation of four buttons can affect the state of the electric fan. The following is illustrated by a state diagram:


If you can't see clearly, there's a state transition table.


In order to give programmers a more intuitive understanding of the specific usefulness of FSM, I will use the finite state machine of the electric fan to demonstrate.

Finite State Machine in Go Language

There are two files in total. fsm.go is the abstract definition of finite state machine. main.go is the presentation of the specific state of finite state machine on the fan. The code is as follows:

// fsm.go
package main

import (
    "fmt"
    "sync"
)

type FSMState string            // state
type FSMEvent string            // Event
type FSMHandler func() FSMState // Processing method and return to new state

// Finite State Machine
type FSM struct {
    mu       sync.Mutex                           // Exclusive lock
    state    FSMState                             // current state
    handlers map[FSMState]map[FSMEvent]FSMHandler // Processing atlases, each state can start a limited number of events, perform a limited number of processing
}

// Get the current state
func (f *FSM) getState() FSMState {
    return f.state
}

// Set the current state
func (f *FSM) setState(newState FSMState) {
    f.state = newState
}

// Adding Event Processing Method to a State
func (f *FSM) AddHandler(state FSMState, event FSMEvent, handler FSMHandler) *FSM {
    if _, ok := f.handlers[state]; !ok {
        f.handlers[state] = make(map[FSMEvent]FSMHandler)
    }
    if _, ok := f.handlers[state][event]; ok {
        fmt.Printf("[warning] state(%s)Event(%s)Defined", state, event)
    }
    f.handlers[state][event] = handler
    return f
}

// event processing
func (f *FSM) Call(event FSMEvent) FSMState {
    f.mu.Lock()
    defer f.mu.Unlock()
    events := f.handlers[f.getState()]
    if events == nil {
        return f.getState()
    }
    if fn, ok := events[event]; ok {
        oldState := f.getState()
        f.setState(fn())
        newState := f.getState()
        fmt.Println("State from [", oldState, "] Become [", newState, "]")
    }
    return f.getState()
}

// Instantiate FSM
func NewFSM(initState FSMState) *FSM {
    return &FSM{
        state:    initState,
        handlers: make(map[FSMState]map[FSMEvent]FSMHandler),
    }
}
// main.go
package main

import (
    "fmt"
)

var (
    Poweroff        = FSMState("Close")
    FirstGear       = FSMState("1 files")
    SecondGear      = FSMState("2 files")
    ThirdGear       = FSMState("3 files")
    PowerOffEvent   = FSMEvent("Press the Close button")
    FirstGearEvent  = FSMEvent("Press 1 button")
    SecondGearEvent = FSMEvent("Press 2 buttons")
    ThirdGearEvent  = FSMEvent("Press 3 buttons")
    PowerOffHandler = FSMHandler(func() FSMState {
        fmt.Println("The electric fan has been turned off")
        return Poweroff
    })
    FirstGearHandler = FSMHandler(func() FSMState {
        fmt.Println("Electric fan open 1 gear, breeze slowly!")
        return FirstGear
    })
    SecondGearHandler = FSMHandler(func() FSMState {
        fmt.Println("Electric fan opens 2 gears, cool and chilly! ______________")
        return SecondGear
    })
    ThirdGearHandler = FSMHandler(func() FSMState {
        fmt.Println("The fan opens three gears and the hairstyle is blown upside down!")
        return ThirdGear
    })
)

// Electric fan
type ElectricFan struct {
    *FSM
}

// Instantiated electric fan
func NewElectricFan(initState FSMState) *ElectricFan {
    return &ElectricFan{
        FSM: NewFSM(initState),
    }
}

// Entry function
func main() {

    efan := NewElectricFan(Poweroff) // The initial state is closed
    // Closed state
    efan.AddHandler(Poweroff, PowerOffEvent, PowerOffHandler)
    efan.AddHandler(Poweroff, FirstGearEvent, FirstGearHandler)
    efan.AddHandler(Poweroff, SecondGearEvent, SecondGearHandler)
    efan.AddHandler(Poweroff, ThirdGearEvent, ThirdGearHandler)
    // 1 gear status
    efan.AddHandler(FirstGear, PowerOffEvent, PowerOffHandler)
    efan.AddHandler(FirstGear, FirstGearEvent, FirstGearHandler)
    efan.AddHandler(FirstGear, SecondGearEvent, SecondGearHandler)
    efan.AddHandler(FirstGear, ThirdGearEvent, ThirdGearHandler)
    // 2 gear status
    efan.AddHandler(SecondGear, PowerOffEvent, PowerOffHandler)
    efan.AddHandler(SecondGear, FirstGearEvent, FirstGearHandler)
    efan.AddHandler(SecondGear, SecondGearEvent, SecondGearHandler)
    efan.AddHandler(SecondGear, ThirdGearEvent, ThirdGearHandler)
    // 3-gear status
    efan.AddHandler(ThirdGear, PowerOffEvent, PowerOffHandler)
    efan.AddHandler(ThirdGear, FirstGearEvent, FirstGearHandler)
    efan.AddHandler(ThirdGear, SecondGearEvent, SecondGearHandler)
    efan.AddHandler(ThirdGear, ThirdGearEvent, ThirdGearHandler)

    // Start testing state changes
    efan.Call(ThirdGearEvent)  // Press 3 buttons
    efan.Call(FirstGearEvent)  // Press 1 button
    efan.Call(PowerOffEvent)   // Press the Close button
    efan.Call(SecondGearEvent) // Press 2 buttons
    efan.Call(PowerOffEvent)   // Press the Close button
}

Return after execution:

The fan opens three gears and the hairstyle is blown upside down!
The state changes from [Close] to [3 stalls]
Electric fan open 1 gear, breeze slowly!
Status changes from [3 stalls] to [1 stalls]
The electric fan has been turned off
 The state changes from [1 stall] to [Close]
Electric fan opens 2 gears, cool and chilly! ______________
The state changes from [Close] to [2 stalls]
The electric fan has been turned off
 The state changes from [2 stalls] to [closed]

Posted by fmpros on Tue, 11 Jun 2019 10:43:13 -0700