用GO实现的erlang的genfsm.
来源:互联网 发布:matlab 2014a for mac 编辑:程序博客网 时间:2024/05/01 22:23
关于erlang的有限状态机,参考erlang四大behaviour之二-gen_fsm这篇文章。
有限状态机可以用下面这个公式来表达
State(S) x Event(E) -> Actions(A), State(S')
这两天正好空闲,就用golang实现了一下,话不多说,直接上代码
package utilimport ("errors""reflect""sync""time""unicode""unicode/utf8""util/log")var typeOfError = reflect.TypeOf((*error)(nil)).Elem()type FSM struct {sync.MutexStopReason stringrcvr reflect.Value // receiver of methods for the servicetyp reflect.Type // type of the receivermethod map[string]reflect.Methodevent chan Eventquit chan intstate stringstopped bool}type Event struct {event stringparam interface{}timeout int}func (fsm *FSM) IsStopped() bool {fsm.Lock()defer fsm.Unlock()return fsm.stopped}func (fsm *FSM) SendEvent(event string, param interface{}) {fsm.Lock()defer fsm.Unlock()if fsm.stopped {return}fsm.event <- Event{event, param, 0}}func (fsm *FSM) Init(start string) error {if _, ok := fsm.method[start]; !ok {return errors.New("not found state")}fsm.state = startgo func() {for {select {case e := <-fsm.event:go fsm.CallState(e)case <-fsm.quit:goto close}}close:close(fsm.event)close(fsm.quit)}()return nil}func (fsm *FSM) CallState(e Event) {fsm.Lock()defer fsm.Unlock()if function, ok := fsm.method[fsm.state]; ok {returnValues := function.Func.Call([]reflect.Value{fsm.rcvr, reflect.ValueOf(e.event), reflect.ValueOf(e.param), reflect.ValueOf(e.timeout)})nextstate := returnValues[0].String()timeout := returnValues[1].Int()errInter := returnValues[2].Interface()errmsg := ""if errInter != nil {errmsg = errInter.(error).Error()}if nextstate == "stop" {fsm.Stop(errmsg)fsm.quit <- 1return}if errmsg != "" {log.LogError(errmsg)}fsm.state = nextstateif timeout > 0 {go fsm.DelayCall(time.Duration(timeout))}}}func (fsm *FSM) DelayCall(timeout time.Duration) {select {case <-time.After(timeout * time.Millisecond):fsm.event <- Event{"timeout", 0, int(timeout)}}}func (fsm *FSM) Stop(message string) {fsm.StopReason = messagefsm.stopped = true}func (fsm *FSM) Close() {fsm.Lock()defer fsm.Unlock()if fsm.stopped {return}fsm.quit <- 1}func NewFSM(fsm interface{}) *FSM {f := &FSM{typ: reflect.TypeOf(fsm), rcvr: reflect.ValueOf(fsm), event: make(chan Event), quit: make(chan int)}f.method = suitableMethods(f.typ, true)return f}func isExported(name string) bool {rune, _ := utf8.DecodeRuneInString(name)return unicode.IsUpper(rune)}func suitableMethods(typ reflect.Type, reportErr bool) map[string]reflect.Method {methods := make(map[string]reflect.Method)for m := 0; m < typ.NumMethod(); m++ {method := typ.Method(m)mtype := method.Typemname := method.Nameif !isExported(mname) {continue}// Method needs four ins: receiver, string, interface{}, int.if mtype.NumIn() != 4 {if reportErr {log.LogError("method", mname, "has wrong number of ins:", mtype.NumIn())}continue}// First arg must be a string.if mtype.In(1).Kind() != reflect.String {if reportErr {log.LogError("method", mname, "arg1 type not a string:", mtype.In(1).Kind())}continue}// Second arg must be a interface.if mtype.In(2).Kind() != reflect.Interface {if reportErr {log.LogError("method", mname, "arg2 type not a interface:", mtype.In(2).Kind())}continue}// Third arg must be a int.if mtype.In(3).Kind() != reflect.Int {if reportErr {log.LogError("method", mname, "arg3 type not a int:", mtype.In(3).Kind())}continue}// Method needs three out.if mtype.NumOut() != 3 {if reportErr {log.LogError("method", mname, "has wrong number of outs:", mtype.NumOut())}continue}if mtype.Out(0).Kind() != reflect.String {if reportErr {log.LogError("method", mname, "out1 type not a string:", mtype.Out(0).Kind())}continue}if mtype.Out(1).Kind() != reflect.Int {if reportErr {log.LogError("method", mname, "out1 type not a int:", mtype.Out(1).Kind())}continue}if mtype.Out(2) != typeOfError {if reportErr {log.LogError("method", mname, "out3 type not a error:", mtype.In(2).Kind())}continue}methods[mname] = method}return methods}
下面就是使用方法:
type GoFSM struct {}func (f *GoFSM) State1(event string, param interface{}, t int) (nextstate string, timeout int, err error) {log.LogMessage(event, param.(int))return "State2", 100, nil //如果timeout大于0,则在timeout毫秒后,自动调用下一个状态,下一个状态的event为timeout}func (f *GoFSM) State2(event string, param interface{}, t int) (nextstate string, timeout int, err error) {log.LogMessage(event)return "stop", 0, errors.New("stop ok") //nextstate=stop则停止状态机,err为停止原因}func main() {f := util.NewFSM(&GoFSM{})f.Init("State1") //初始状态f.SendEvent("Do", 1) //发送事件time.Sleep(time.Second * 1)}
所有的状态回调函数,必须以大写字母开头,原型必须是
func(event string, param interface{}, t int) (nextstate string, timeout int, err error)event是事件名,param为事件的参数,t>0表示这是一个延时事件。返回值:nextstate为新的状态,必须和状态回调函数同名,如果为"stop"则表示没有后续的状态,状态机停止。timeout>0表示延时回调,将在timeout时间后,产生一个timeout事件。
0 0
- 用GO实现的erlang的genfsm.
- 关于Go 和Erlang的一些想法
- Erlang & Go 的IO优化策略简介
- MapReduce的Erlang实现
- [Erlang 0032] Erlang Binary的内部实现
- Erlang和Go的并行化concurrent比较
- 使用erlang实现的quicksort
- Erlang数据类型的内部实现
- erlang中dict的实现
- erlang catch的内部实现
- Erlang数据类型的内部实现
- go的websocket实现
- go的接口实现
- go的grpc实现
- Erlang,优秀的Erlang
- 用GO实现的冒泡算法
- [Erlang]用erlang实现binary_to_term
- 超简单的Erlang复数实现
- 堆栈、栈帧与函数调用过程分析
- Eclipse—添加DTD文件实现XML的自动提示功能
- HI,新家
- CUDA编译结果与CPU结果不一致
- Sip基础三
- 用GO实现的erlang的genfsm.
- 软件设计6大原则
- 私塾在线链接
- 分布式文件系统Hadoop、GoogleFS、RAID介绍
- Android StackBox 分屏效果
- Princeton Algorithms: Part 1 [week 4: Priority Queues]
- Android实现任务管理器
- 新入行程序员应知的十个秘密
- 利用kinnect识别语音,通过NRF24L01控制小车运动——实验课设