有限状态机编程

1.概念

有限状态机,(英语:Finite-state machine, FSM),又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。

2.数据中继

终端1向终端2发送数据,然后终端2进行处理后,在发送回终端1
也就是一个myCpy的重构
在这里插入图片描述

3.代码

#define TTY1 "/dev/tty11"
#define TTY2 "/dev/tty12"
#define BUFSIZE 20

enum{ STATE_R = 1, STATE_W, STATE_EX, STATE_T};

struct fsm_st
{
        int State;
        int sfd;
        int dfd;
        char Buf[BUFSIZE];
        int Len;
        int Pos;
        char *ErrString;
};


void fsm_driver(struct fsm_st *p)
{
        int Len;

        switch(p->State)
        {
          case STATE_R:
                p->Len = read(p->sfd, p->Buf, BUFSIZE);
                if(0 == p->Len)//已经读取完成全部
                        p->State = STATE_T;
                else if(p->Len < 0)
                {
                        if(EAGAIN == errno)//假错
                                p->State = STATE_R;
                        else//真错
                        {
                                p->State = STATE_EX;
                                p->ErrString = "Read Err";
                        }
                }
                else//读取成功
                {
                        p->Pos = 0;
                        p->State = STATE_W;
                }
                break;
          case STATE_W:
                Len = write(p->dfd, p->Buf + p->Pos, p->Len);
                if(Len < 0)
                {
                        if(EAGAIN == errno)//假错
                                p->State = STATE_W;
                        else//真错
                        {
                                p->State = STATE_EX;
                                p->ErrString = "Write Err";
                        }

                }
                else
                {
                        p->Pos += Len;
                        p->Len -= Len;
                        if(0 == p->Len)//写入完成
                                p->State = STATE_R;
                        else    //如果没有写够 
                                p->State = STATE_W;
                }

                break;
          case STATE_EX:
                perror(p->ErrString);
                p->State = STATE_T;

                break;
          case STATE_T:
                // Do Something
                break;
          default:
                abort();
                break;

        }
}


void relay(int fd1, int fd2)
{
        int fd1_save;
        int fd2_save;
        struct fsm_st fsm12, fsm21;

        //不能确定哪个是阻塞哪个是非阻塞
        fd1_save = fcntl(fd1,F_GETFL);
        fcntl(fd1, F_SETFL, fd1_save|O_NONBLOCK);

        fd2_save = fcntl(fd2,F_GETFL);
        fcntl(fd2, F_SETFL, fd2_save|O_NONBLOCK);

        fsm12.State = STATE_R;
        fsm12.sfd = fd1;
        fsm12.dfd = fd2;

        fsm21.State = STATE_R;
        fsm21.sfd = fd2;
        fsm21.dfd = fd1;


        while(STATE_T == fsm12.State || STATE_T == fsm21.State)
        {
                fsm_driver(&fsm12);
                fsm_driver(&fsm21);
        }

        fcntl(fd1, F_SETFL, fd1_save);
        fcntl(fd2, F_SETFL, fd2_save);


}


int main()
{
        int fd1, fd2;

        fd1 = open(TTY1, O_RDWR);
        if(fd1 < 0)
        {
                perror("open()");
                exit(1);
        }

        fd2 = open(TTY2, O_RDWR|O_NONBLOCK);
        if(fd2 < 0)
        {
                perror("open()");
                exit(1);
        }


        close(fd2);
        close(fd1);

        return 0; 
}

4.中继引擎实例

relayer.h

#ifndef RELAYER_H__
#define RELAYER_H__

#include <stdint.h>
#define   REL_JOBMAX  10000
enum {
	STATE_RUNNING = 1,
	STATE_CANCELED,
	STATE_OVER
};
struct rel_stat_st {
	int state;
	int fd1;
	int fd2;
	int64_t count12, count21;//1向2发送了多少字节,2向1发送了多少字节
};


int rel_addjob(int fd1, int fd2);
/*
	return >= 0			成功,返回当前任务ID
		   == -EINVAL	失败,参数非法
		   == -ENOSPC   失败,任务数组满
		   == -ENOMEM   失败,内存分配有误
*/



int rel_canceljob(int id);
/*
	return == 0			成功,指定任务成功取消
		   == -EINVAL	失败,参数非法
		   == -EBUSY    失败,任务早已被取消
*/



int rel_waitjob(int id, struct rel_stat_st*);
/*
	return == 0			成功,指定任务已终止并返回状态
		   == -EINVAL	失败,参数非法
		
*/



int rel_statjob(int id, struct rel_stat_st*);
/*

	return == 0			成功,指定任务状态返回
		   == -EINVAL	失败,参数非法

*/
#endif


relayer.c

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<pthread.h>
#include <unistd.h>
#include"relayer.h"
#include<string.h>
#include<fcntl.h>



static struct rel_job_st* rel_job[REL_JOBMAX];
static pthread_mutex_t mut_rel_job = PTHREAD_MUTEX_INITIALIZER;
static pthread_once_t init_once = PTHREAD_ONCE_INIT;
enum {
	//几种状态
	STATE_R,
	STATE_W,
	STATE_EX,
	STATE_T
};

#define   BUFSIZE  1024


//状态机
struct rel_fsm_st {
	int state;//记录状态
	int sfd;//源文件
	int dfd;//目的文件
	char buf[BUFSIZE];//中间缓冲区
	int len;//读到的长度
	int pos;//写的过程如果一次没有写完,记录上次写的位置
	char* err;//错误信息
	int64_t count;
};


//每一对终端结构体
struct rel_job_st{
	//两个终端
	int fd1;
	int fd2;
	//该对终端状态STATE_RUNNING,STATE_CANCELED, STATE_OVER
	int job_state;
	//两个终端的状态机结构体
	struct rel_fsm_st fsm12, fsm21;
	//用来退出复原状态
	int fd1_save, fd2_save;

};

//状态转移函数
static void fsm_driver(struct rel_fsm_st* fsm) {
	int ret;
	switch (fsm->state) {
	case STATE_R:
		fsm->len = read(fsm->sfd, fsm->buf, BUFSIZE);
		if (fsm->len == 0)
			fsm->state = STATE_T;
		else if (fsm->len < 0) {
			if (errno == EAGAIN)
				fsm->state = STATE_R;
			else {
				fsm->err = "read()";
				fsm->state = STATE_EX;
			}

		}
		else {
			fsm->pos = 0;
			fsm->state = STATE_W;
		}

		break;
	case STATE_W:
		ret = write(fsm->dfd, fsm->buf + fsm->pos, BUFSIZE);
		if (ret < 0) {
			if (errno == EAGAIN)
				fsm->state = STATE_W;
			else {
				fsm->err = "write()";
				fsm->state = STATE_EX;
			}

		}
		else {
			fsm->pos += ret;
			fsm->len -= ret;
			if (fsm->len == 0)
				fsm->state = STATE_R;//写完了再去读
			else
				fsm->state = STATE_W;//没写完继续写
		}
		break;
	case STATE_EX:
		perror(fsm->err);
		fsm->state = STATE_T;
		break;
	case STATE_T:
		/*  do smoething*/
		break;
	default:
		abort();
		break;

	}
}


static void* thr_relayer(void *p) {
	int i;
	while (1) {
		pthread_mutex_lock(&mut_rel_job);
		for (i = 0; i < REL_JOBMAX; i++) {
			if (rel_job[i] != NULL) {
				if (rel_job[i]->job_state == STATE_RUNNING) {
					fsm_driver(&rel_job[i]->fsm12);
					fsm_driver(&rel_job[i]->fsm21);
					if (rel_job[i]->fsm12.state == STATE_T && rel_job[i]->fsm21.state == STATE_T)
						rel_job[i]->job_state = STATE_OVER;
				}
			}
		}
		pthread_mutex_unlock(&mut_rel_job);
	}
	
}

static void module_load(void) {
	int err;
	pthread_t tid_relayer;
	err = pthread_create(&tid_relayer, NULL, thr_relayer, NULL);
	if (err) {
		fprintf(stderr, "pthread_create():%s\n", strerror(err));
		exit(1);
	}

}

static int get_free_pos_unlocked() {
	int i;
	for (i = 0; i < REL_JOBMAX; i++) {
		if (rel_job[i] == NULL)
			return i;
	}
	return -1;
}

int rel_addjob(int fd1, int fd2) {
	struct rel_job_st *me;
	int pos;

	pthread_once(&init_once, module_load);
	me = malloc(sizeof(*me));
	if (me == NULL)   //空间问题
		return -ENOMEM;
	me->fd1 = fd1;
	me->fd2 = fd2;
	me->job_state = STATE_RUNNING;//该对终端设置正在运行

	me->fd1_save = fcntl(me->fd1, F_GETFL);
	fcntl(me->fd1, F_SETFL, me->fd1_save | O_NONBLOCK);  //非阻塞	打开

	me->fd2_save = fcntl(me->fd2, F_GETFL);
	fcntl(me->fd2, F_SETFL, me->fd2_save | O_NONBLOCK);//非阻塞	打开

	me->fsm12.sfd = me->fd1;
	me->fsm12.dfd = me->fd2;
	me->fsm12.state = STATE_R;

	me->fsm21.sfd = me->fd2;
	me->fsm21.dfd = me->fd1;
	me->fsm21.state = STATE_R;

	pthread_mutex_lock(&mut_rel_job);
	pos = get_free_pos_unlocked();
	if (pos < 0) {
		pthread_mutex_unlock(&mut_rel_job);
		fcntl(me->fd1, F_SETFL, me->fd1_save);
		fcntl(me->fd2, F_SETFL, me->fd2_save);
		free(me);
		return -ENOSPC;
	}
	rel_job[pos] = me;
	pthread_mutex_unlock(&mut_rel_job);
	return pos;

}


int rel_canceljob(int id);
/*
	return == 0			成功,指定任务成功取消
		   == -EINVAL	失败,参数非法
		   == -EBUSY    失败,任务早已被取消
*/



int rel_waitjob(int id, struct rel_stat_st*);




int rel_statjob(int id, struct rel_stat_st*);

main.c

#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include<errno.h>
#include<string.h>
#include"relayer.h"


//两个设备为一对互传数据
#define     TTY1       "/dev/tty11"
#define     TTY2       "/dev/tty12"


#define     TTY3       "/dev/tty10"
#define     TTY4       "/dev/tty9"


int main(int argc, char** argv) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
	int fd1, fd2, fd3, fd4;
	int job1, job2;
	fd1 = open(TTY1, O_RDWR);//先以阻塞打开(故意先阻塞形式)
	if (fd1 < 0) {
		perror("open()");
		exit(1);
	}
	write(fd1, "TTY1\n", 5);
	fd2 = open(TTY2, O_RDWR|O_NONBLOCK);//非阻塞
	if (fd2 < 0) {
		perror("open()");
		exit(1);
	}
	write(fd2, "TTY2\n", 5);

	job1 = rel_addjob(fd1, fd2);//添加一对终端互传数据  
	if (job1 < 0) {
		fprintf(stderr, "rel_addjob():%s\n", strerror(-job1));
		exit(1);
	}
	


	fd3 = open(TTY3, O_RDWR);//先以阻塞打开(故意先阻塞形式)
	if (fd3 < 0) {
		perror("open()");
		exit(1);
	}
	write(fd3, "TTY3\n", 5);
	fd4 = open(TTY4, O_RDWR | O_NONBLOCK);//非阻塞
	if (fd4 < 0) {
		perror("open()");
		exit(1);
	}
	write(fd4, "TTY4\n", 5);

	job2 = rel_addjob(fd3, fd4);//添加一对终端互传数据  
	if (job2 < 0) {
		fprintf(stderr, "rel_addjob():%s\n", strerror(-job2));
		exit(1);
	}

	while (1)
		pause();

	close(fd4);
	close(fd3);
	close(fd2);
	close(fd1);
	
	exit(0);

}

这段代码的问题主要是一直占用着cpu, 一直报EAGAIN假错(等待一端读或者写)

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在MATLAB中,可以使用状态机工具箱来实现有限状态机序列编程。 首先需要安装状态机工具箱,然后可以使用以下命令创建一个简单的状态机: ``` s = fsm(3); % 创建一个3状态的状态机 s.StateNames = {'State1','State2','State3'}; % 给每个状态命名 s.InitialState = 'State1'; % 设置初始状态为State1 s.StateActions = {@state1Action,@state2Action,@state3Action}; % 设置每个状态的动作函数 s.TransitionActions = {@transitionAction1,@transitionAction2,@transitionAction3}; % 设置每个转移的动作函数 ``` 然后可以使用以下命令执行状态机: ``` [state, output] = run(s, input); ``` 其中,input是输入序列,state是最终状态,output是输出序列。 在动作函数中,可以实现任意的MATLAB代码来处理输入和输出。在转移动作函数中,可以根据输入来决定状态转移。 例如,下面是一个简单的状态机,它将输入的数字序列转换为二进制并输出: ``` function [state, output] = digitToBinary(input, state) switch state case 1 % 初始状态 output = ''; if input >= 0 && input <= 9 state = 2; else state = 3; end case 2 % 数字状态 output = dec2bin(input); state = 1; case 3 % 错误状态 output = 'Error: Input must be between 0 and 9.'; state = 1; end end ``` 在这个状态机中,第一个状态是初始状态,第二个状态是数字状态,第三个状态是错误状态。当输入是一个数字时,状态将从初始状态转移到数字状态,并将输出设置为输入的二进制表示。当输入不是数字时,状态将从初始状态转移到错误状态,并将输出设置为错误消息。 可以使用以下命令来测试这个状态机: ``` s = fsm(3); s.StateNames = {'Initial','Digit','Error'}; s.InitialState = 'Initial'; s.StateActions = {@()[], @digitToBinary, @()[]}; s.TransitionActions = {@()[], @()[], @()[]}; [input, output] = textread('input.txt','%d %s'); for i = 1:length(input) [s, output{i}] = run(s, input(i)); end ``` 其中,input.txt是一个包含数字序列的文本文件,每一行是一个数字。这个程序将读取文本文件并使用状态机将每个数字转换为二进制,并将结果输出到output变量中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值