推荐一个开源的轻量级任务调度器!TaskScheduler!
大家好,我是麦鸽。
这次推荐一款轻量级的嵌入式任务调度器,目前已经有1.4K
的star
,这个项目比较轻量化,只有5个源文件,可以作为学习的一个开源项目。
项目概述:
这是一个轻量级的协作式多任务处理(任务调度)实现。相比于抢占式编程和像 FreeRTOS 这样的框架,它提供了一种更简单的替代方案。
为什么是协作式的?
使用协作式处理时,我们无需过多担心并发处理中的陷阱(如竞态条件、死锁、活锁、资源共享等)。
协作式处理的设计天然地解决了这些问题。
正如 Herb Sutter(ISO C++ 标准委员会主席,微软公司)所说:
“每个学习并发编程的人,都认为自己理解了它,但最终都会发现自己遇到了原本认为不可能发生的竞态条件,发现自己其实并没有真正理解它。”
主要特点:
周期性任务执行,支持动态的执行周期(默认是毫秒,也可以启用微秒精度)——执行频率
任务迭代次数(有限或无限次迭代)
预定义顺序执行任务
动态调整任务执行参数(频率、迭代次数、回调方法)
省电模式,当没有任务调度时进入空闲睡眠模式
支持通过状态请求对象(Status Request)进行事件驱动的任务调用
支持任务ID和控制点,用于错误处理和看门狗定时器
支持本地任务存储指针(允许多个任务共享相同的回调代码)
支持分层任务优先级
支持
std::function
(仅在 ESPx 和 STM32 测试过)任务超时功能
支持静态和动态回调方法绑定
提供 CPU负载/空闲统计,适用于时间敏感型应用
支持带有优先级的调度选项(原始调度的优先级及间隔,包括是否处理调度遗漏)
能够暂停/恢复和启用/禁用调度
在抢占式调度器(如 FreeRTOS)下提供线程安全的调度
支持动态创建的任务在禁用时自动销毁
支持在 FreeRTOS 下的“无滴答”执行(持续睡眠直到下一次调度任务调用)
调度开销:每次调度约 15 至 18 微秒(以 Arduino UNO rev 3,16MHz 时钟为例,单一调度器,不带优先级)
兼容平台:
TaskScheduler 已在以下平台上进行过测试:
Arduino Uno R3
Arduino Nano
Arduino Micro
ATtiny85
ESP8266
ESP32
Teensy(测试过 Teensy 3.5)
nRF52(测试过 nRF52832)
nRF52 Adafruit Core(测试过 nRF52840,v3.6.2 修复版)
STM32(测试过 Mini USB STM32F103RCBT6 ARM Cortex-M3,Leaflabs Leaf maple mini 模块 F)
MSP430 和 MSP432 开发板
Raspberry Pi(需要外部的 Arduino.h 和 millis() 实现)
该项目为实现协作式多任务处理提供了一个简洁而高效的方案,尤其适用于需要周期性任务和节能模式的嵌入式系统。
如何使用?
项目里已经提供了大量的样例程序,不过都是基于Arduino
平台,也都是比较好理解的;
下面是一段调度器使用的模板程序,具体如何使用,可以参考一下;
// ==== Debug and Test options ==================
#define _DEBUG_
//#define _TEST_
//===== Debugging macros ========================
#ifdef _DEBUG_
#define SerialD Serial
#define _PM(a) SerialD.print(millis()); SerialD.print(": "); SerialD.println(a)
#define _PP(a) SerialD.print(a)
#define _PL(a) SerialD.println(a)
#define _PX(a) SerialD.println(a, HEX)
#else
#define _PM(a)
#define _PP(a)
#define _PL(a)
#define _PX(a)
#endif
#include <TaskScheduler.h>
Scheduler ts;
void task1Callback();
void task2Callback();
// ==== Task definitions ========================
Task t1 (100 * TASK_MILLISECOND, TASK_FOREVER, &task1Callback, &ts, true);
Task t2 (TASK_IMMEDIATE, 100 /* times */, &task2Callback, &ts, true);
void setup() {
// put your setup code here, to run once:
#if defined(_DEBUG_) || defined(_TEST_)
Serial.begin(115200);
delay(2000);
_PL("Scheduler Template: setup()");
#endif
}
// main loop
void loop() {
ts.execute();
}
void task1Callback() {
_PM("task1Callback()");
// task code
}
void task2Callback() {
_PM("task2Callback()");
// task code
}
项目地址:https://github.com/arkhipenko/TaskScheduler
往期推荐
新手必看!C语言精华知识:表驱动法
9条必学的嵌入式C语言调试技巧!宏定义的妙用
踩坑了!嵌入式C语言常见的几个陷阱!你遇到过吗?
嵌入式开发又遇到BUG?怎么办?教你几招直接起飞
现成轮子OSAL操作系统抽象层的移植