基于回调的事件驱动或者逻辑控制
本文提供了一种单线程编程思路,并简单实现了该思路。
受PLC编程线圈和触点概念的启发。
将程序抽象理解成一条条因果逻辑,即条件和动作。
当条件满足时执行动作。
实现业务逻辑时只需要将条件和动作对应实现。
回过头来一想这不就是QT的信号槽吗?
更一般的概念,程序就是处理输入输出。线圈是输入,触点是输出。信号是输入,槽是输出。条件是输入,动作是输出。概念都是相通的。
本实现特点
1.将条件和动作关联起来管理,区别于一般的事件驱动。
2.使用void指针,条件函数和动作函数都可以有参数。
3.例子里使用数组实现命令表,适合MCU,也可以使用链表。
代码
接口
/*cmd.h*/
#ifndef FILE_CMD_H
# define FILE_CMD_H
# define MAX_CMD_NUM 100
# define CMD_FALSE 0
# define CMD_TRUE (!CMD_FALSE)
typedef unsigned int(*fp_condition_t)(void *);
typedef void (*fp_action_t)(void *);
typedef struct
{
fp_condition_t cond_cb;//condition
fp_action_t act_cb;//action
void* cond_para;
void* act_para;
}cmd_t;
int cmd_init();
int cmd_add(cmd_t* p_cmd);
int cmd_del(int cmd_id);
int cmd_process();
#endif // FILE_CMD_H
实现
/*cmd.c*/
#include "cmd.h"
# ifndef NULL
# define NULL ((void*)0)
# endif
cmd_t* cmd_table[MAX_CMD_NUM]={0};
/*初始化清空命令表*/
int cmd_init()
{
int i = 0;
for(i = 0;i < MAX_CMD_NUM;i++)
{
cmd_table[i] = NULL;
}
}
/*向命令表中添加命令,成功返回在表中的位置*/
int cmd_add(cmd_t* p_cmd)
{
int i = 0;
for(i = 0;i < MAX_CMD_NUM;i++)
{
if(NULL == cmd_table[i])
{
cmd_table[i]=p_cmd;
return i;
}
}
return -1;//out of memory
}
/*删除命令*/
int cmd_del(int cmd_id)
{
cmd_table[cmd_id]=NULL;
}
/*命令处理,遍历命令表,执行满足条件的命令的动作*/
int cmd_process()
{
int i = 0;
for(i = 0;i < MAX_CMD_NUM;i++)
{
cmd_t* cmd = cmd_table[i];
if(cmd!= NULL)
{
if(cmd->cond_cb != NULL)
{
if(CMD_FALSE != cmd->cond_cb(cmd->cond_para))
{
if(cmd->act_cb != NULL)
{
cmd->act_cb(cmd->act_para);
}
}
}
}
}
}
用法
/*main.c*/
#include <stdio.h>
#include "cmd.h"
unsigned int cond_hello(void * p_time)
{
int time=*(int*)p_time;
if(time == 1 )
{
return CMD_TRUE;
}
return CMD_FALSE;
}
unsigned int cond_bye(void * p_time)
{
int time=*(int*)p_time;
if(time == 5 )
{
return CMD_TRUE;
}
return CMD_FALSE;
}
void act_hello(void * name)
{
printf("hello %s \n",(char *)name);
}
void act_bye(void * name)
{
printf("bye %s \n",(char *)name);
}
void main(void)
{
unsigned int time = 0;
char* name_ryan = "ryan";
char* name_Mr_White = "Mr White";
cmd_t hello_ryan = {.cond_cb = cond_hello,
.act_cb = act_hello,
.cond_para = &time,
.act_para = name_ryan };
cmd_t bye_ryan = {.cond_cb=cond_bye,
.act_cb=act_bye,
.cond_para = &time,
.act_para = name_ryan };
cmd_t hello_white = {.cond_cb = cond_hello,
.act_cb = act_hello,
.cond_para = &time,
.act_para = name_Mr_White };
cmd_t bye_white = {.cond_cb=cond_bye,
.act_cb=act_bye,
.cond_para = &time,
.act_para = name_Mr_White };
cmd_init();
cmd_add(&hello_ryan);
cmd_add(&bye_ryan);
cmd_add(&hello_white);
cmd_add(&bye_white);
while(1)
{
sleep(1);
time++;
cmd_process();
}
}