事件驱动多任务框架

事件驱动多任务框架

先上github传送门

这是一个面向嵌入式系统的轻量级多任务框架。它使用事件驱动的方式,通过发布订阅模式来实现任务间的解耦和通信。

整体设计

  • 任务(Task):每个独立的功能单元可以抽象为一个任务,任务有唯一ID,通过初始化和事件回调函数实现具体逻辑。

  • 事件(Event):事件用于任务间传递信息和通信。事件有优先级,用于决定调度顺序。

  • 定时器(Timer):定时器周期性产生事件,用于触发定时任务。

  • 环形缓存(Ring Buffer):用环形缓存实现事件队列和任务事件队列,以节省内存。

  • 任务表(Task Table):保存所有任务信息,在初始化阶段构建。

  • 事件订阅表(Event Subscribe Table):记录每个事件的订阅者,用于事件分发。

优点

  • 轻量级,适合资源受限的嵌入式系统
  • 良好的可扩展性,可以很容易添加新的任务和事件
  • 使用订阅发布模式,任务解耦,方便修改和维护
  • 支持任务间优先级和通信
  • 良好的可读性和可移植性

总体来说,这是一个轻量级的多任务框架,使用事件驱动编程模型,很适合嵌入式系统的多任务场景,可以提高系统的扩展性和健壮性。

编译运行

安装 PyBuildKit

curl -fsSL https://raw.githubusercontent.com/skb666/PyBuildKit/master/install.sh | bash
. $HOME/.mysdk/env

编译

python ./project build

运行

python ./project run

接口说明

主程序接口

周期运行以下接口,作为虚拟定时器及任务延时驱动源

timer_increase();
timer_loop();
task_time_loop();

主程序中用以下接口对所有任务做初始化

task_init();

程序主循环中调用以下接口以实时处理用户任务

task_loop();

用户定时器

用户定时器用于周期性产生定时器事件

用户定时器结构体如下:

typedef struct _TIMER {
    EVENT_TYPE event_type;  // 定时器产生的事件类型
    uint32_t priority;      // 事件优先级
    uint32_t reload;        // 重载时间
    uint32_t tick;          // 内部计时器
    int32_t times;          // 事件产生次数
} TIMER;

添加用户定时器

  1. task_user.hEVENT_TYPE 中添加定时器到达指定时间后产生的事件名称
  2. timer_user.hTIMER_TICK 中添加对应事件触发需要的时间
  3. timer_user.cs_timer_list 中增加一个定时器,格式参照结构体 TIMER

用户任务

用户任务结构体如下:

typedef struct _TASK {
    uint32_t id;                            // 任务 ID
    int32_t times;                          // 任务剩余执行次数,负数表示无穷次
    uint32_t delay;                         // 任务延迟时间
    void (*init)(void);                     // 任务初始化回调
    void (*handle)(struct _TASK *);         // 任务处理回调
    EVENT events_buffer[TASK_EVENT_MAX];    // 内部使用,作为下面字段的 buffer
    RING_FIFO events;                       // 任务事件缓冲区
} TASK;

当主函数中执行 task_init() 时会遍历用户任务列表,对每个任务做初始化并执行任务初始化回调。

在任务初始化回调中一般进行事件注册,使用接口如下:

int8_t task_event_subscribe(EVENT_TYPE type, uint32_t id);                  // 订阅任务事件
int8_t task_event_unsubscribe(EVENT_TYPE type, uint32_t id);                // 取消订阅任务事件
int8_t task_event_publish(EVENT_TYPE type, void *data, uint32_t priority);  // 发布任务事件

每当有任务事件产生时,内部会先将任务事件分发给订阅了该事件的任务,保存于任务事件缓冲区以进行下一步处理。

任务处理回调中可以从 TASKevents 接收事件,并进行对应处理;除此之外,可以通过发布任务事件来进行任务事件编排,在 task_user.hEVENT_TYPE 中可以添加自定义任务事件。

当结束事件处理后,可以通过以下接口来减少任务剩余执行次数:

void task_update_times(TASK *task);

问:为什么不将“任务剩余次数递减”作为内部流程?
答:任务回调中进行了事件处理,会有“指定事件处理完成后才算一次处理”的需求,开放接口可以使更加灵活。

添加用户任务

  1. task_user.hTASK_ID 中添加任务 ID
  2. task_user.cs_task_list 中添加任务,格式参照结构体 TASK
基于事件驱动的网络框架源码 首先看一下Server类,这个类就是整个框架的核心类,在这个类中只需要 s=new Server(8883,4); s->setUserConnectionCallback(onConnect); s->setUserMessageCallBack(onMessage); s->start(); 就可以启动一个4个线程在8883端口监听的完整的网络程序,其中的两个onXXX就是网络程序需要处理的业务 Server类中包括了有一个重要的类叫做Eventlooper这个类就是对epoll的封装,要用epoll_ctl注册到epoll上的fd又被封装为Channel类,当有数据到来需要操作时,channel中的几个函数指针就指向了需要回调的函数, 这里使用了boost库的function 其中的函数定义为: typedef boost::function EventCallBack; 在epoll返回的时候Eventlooper会遍历可以操作的所有channel,并调用其成员函数handleEvent,该函数会判断events,也就是EPOLLIN EPOLLPRI等,并更具相应的需要去调用处理函数。 这里的Channel并不直接使用而是做基类存在的,更直接的操作在Acceptor和TcpConnection中,其中的 Acceptor 对应了接受连接的socketfd,而TcpConnection则封装了socket的读写操作,在Server的构造函数中会创建一个Acceptor类,真正accept成功以后又会调用到Server的OnConnection函数中,这个函数会根据每个线程的负载将客服端连接的fd注册进相应线程的epoll(当然在单线程的情况下就只有一个epoll)。最后一个作为缓冲区的类charbuff,用链表将单个7KB的缓冲区穿在一起,当数据大于7kb的时候会自动将其释放,避免内存不足,如果数据的块数多余一块那么发送数据就会调用writev。至此整个框架的流程就都已经清楚了,一个简单的实现。 在此还要感谢一下linux多线程网络服务器编程的作者陈硕,CINF的实现部分就是参考其网络框架muduo来的。
一个嵌入式事件驱动框架一般会包含以下几个关键组件: 1. 事件处理器(Event Handler):这是一个用于处理事件的函数或方法。当一个事件被触发时,相应的事件处理器会被调用。 2. 事件队列(Event Queue):这是一个存储事件的队列,所有即将发生的事件都会被加入到队列中。当事件被触发时,事件处理器会从队列中取出相应的事件并进行处理。 3. 事件触发器(Event Trigger):这是一个用于触发事件的函数或方法。当某个条件满足时,相应的事件触发器会被调用,从而触发相应的事件并加入到事件队列中。 4. 事件循环(Event Loop):这是一个无限循环的过程,它不断地从事件队列中取出事件,并将其交给相应的事件处理器进行处理。当事件队列为空时,事件循环会进入休眠状态,等待新的事件被加入到队列中。 基于以上组件,我们可以设计一个简单的嵌入式事件驱动框架的流程如下: 1. 在初始化过程中,创建一个事件队列,以及一个或多个事件触发器。 2. 进入事件循环。在循环中,不断地从事件队列中取出事件。 3. 对于每个事件,将其交给相应的事件处理器进行处理。 4. 在事件处理器中,根据事件类型进行相应的操作。如果需要触发新的事件,可以通过事件触发器来实现。 5. 当所有事件都处理完毕后,进入休眠状态,等待新的事件被加入到队列中。 需要注意的是,在嵌入式系统中,事件处理器的执行时间必须尽可能短,以避免阻塞其他任务的执行。因此,可以考虑采用一些轻量级的事件处理器,例如状态机、定时器等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值