第一章:Protothreads的OS拓展

背景

原生的protothreads是一个具备的任务调度的系统,但当和RTOS的进行对标时,就会显示出明显差距,例如无sleep功能,消息同步手段匮乏,无超时控制等。为了弥补protothreads的这些差距,拓展了protothreads 并命名为PTOS的(protothreads operating system)

PTOS 综述

PTOS是一个非抢式无堆栈操作系统,所有的线程具备相同优先级,内置(event)事件旗标,(sem)信号量、(queue)消息队列、(box)广播式邮箱等消息同步机制。内置timer server线程,支持轻量级软件定时器仅需8字节,创建一个新线程开销仅需32字节。集成线程监控和管理API,低功耗组件,无任何CPU专属代码,移植仅需实现system tick接口即可。以下是PTOS线程结构图1:
在这里插入图片描述

  • Main 指的是裸机的Main,在PTOS中充当root thread
  • 一级节点,表示通过pt_thread_register 接口注册root字节下的,绿色的表示可运行态的。
  • 二级节点,表示通过PT_SPAWN_EX 接口挂载在某一级节点下的子线程, 夫线程和由其衍生出来的子线程(孙子线程)有且仅有一个处于可运行态
  • 三级节点、及其以下,和其父节点关系,等同二级节点和其夫节点的关系

其数据结构如下:

typedef char (*pt_thread_t)(struct pt *);

typedef struct
{
    uint32_t status:4;
    uint32_t timeout_tick:28;
    uint32_t start_tick;
} pt_timer_t;

typedef struct
{
    uint32_t begin          : 1;
    uint32_t idle           : 1;
    uint32_t time_out       : 1;
    uint32_t super          : 1;
    uint32_t yield_cnt      : 8;
    uint32_t yield_run_cnt  : 8;
    uint32_t monitor_enbale : 1;
    uint32_t monitor_view   : 1;
    uint32_t no_use         : 10; 
} pt_thread_status;

typedef struct
{
    slist_t list;
#if PT_MONITOR_FUNC_ENABLE
    const uint8_t *pt_monitor;
#endif
    struct pt pt;
    slist_t sub_head; 
    pt_thread_t pt_thread;
    pt_thread_status status;
    pt_timer_t timer;
} pt_thread_info;

由于PTOS属于非抢占式操作系统,因此每一个线程设计时必须具备主动释放cpu的使用权(注: PTOS核心是原理上时轮询式状态机系统,轮询式状态机系统详情阅读《序章:Protothreads的原生特性》

PTOS 的组成文件

PTOS 由原生的protothreads的三个文件:lc-switch.h、lc.h、pt.h和PTOS本身的pt_box_extern.c、pt_box_extern.h、pt_queue_extern.c、pt_queue_extern.h、pt_sem_extern.c、pt_sem_extern.h、pt_event_extern.c、pt_event_extern.h、pt_timers.c、pt_timers.h、pt_threads.c、pt_threads.h、pt_monitor.c、pt_monitor.h文件组成。

文件功能
lc-switch.h、lc.h、pt.hprotothreads原生文件,提供任务调度功能
pt_timers.*提供时钟管理功能,内嵌soft_timers_thread
pt_threads.*提供时提供线程管理功能,例如线程注册,运行等
pt_queue*提供线程间使用消息队列同步功能
pt_sem*提供线程间使用信号量同步功能
pt_event*提供线程间使用事件旗标同步功能
pt_box*提供线程间使用广播式邮箱同步功能
pt_monitor.*debug时提供确认线程运行状态功能

PTOS 的外部接口简介

PTOS提供了丰富的接口,用以下表格进行简单介绍。在本栏目的其他文件再做详细的介绍

系统接口

pt_threads和pt_timers.h 属于PTOS的最核心的部分,具体原理会在《第二章:PTOS的时钟管理》和《第三章:PTOS的线程管理》描述。

  • pt_threads.h 主要提供以下, 部分可参考作用请参考《序章:Protothreads的原生特性》
线程接口名称含义
void pt_threads_init(void);PTOS初始化函数,main函数初始化调用
int pt_threads_run(void)PTOS运行函数,main函数轮询
uint32_t pt_threads_get_block_time_ms(void);获取图1的root线程的最小阻塞时间
uint32_t pt_thread_get_block_time_ms(pt_thread_info *pti);获取某一节点最小阻塞时间
void pt_thread_register(pt_thread_info *pti, pt_thread_t ptt, const uint8_t *pt_monitor);注册线程
void pt_thread_unregister(pt_thread_info *pti) ;注销线程
PT_BEGIN_EX(pt);继承并拓展PT_BEGIN,
PT_END_EX(pt)继承并拓展PT_END
PT_EXIT_EX(pt)继承并拓展PT_END
PT_WAIT_UNTIL_EX(pt)继承并拓展PT_WAIT_UNTIL_EX
PT_SPAWN_EX(pt)继承并拓展PT_SPAWN_EX
PT_SLEEP_MS(pt, ms)线程休眠函数,单位毫秒
PT_IS_TIMEOUT(pt)线程唤醒原因是否是超时
  • pt_timers.h 主要提供以下功能。
定时器接口名称含义
int pt_timers_server_init(void);软件定时器服务初始化
int pt_timer_register(timer_extern_t *t, timers_callback_t cb);注册软件定时回调函数
int pt_timer_start(pt_timer_t *t, uint32_t ms);开启定时器
int pt_timer_stop(pt_timer_t *t);关闭定时器
uint32_t timers_server_get_block_time_ms(void);软件定时器服务挂起的最小时间

同步接口

event、sem、queue都属于PTOS的同步接口,具体原理会在《第四章:PTOS的同步机制 》描述,其中box比较特殊,具体原理将放到《第五章:PTOS的广播式邮箱》描述

  • pt_sem_extern.h 主要提供以下接口
信号量接口名称含义
void pt_sem_init(pt_sem_t *sem, uint8_t bin);初始化信号量
void pt_sem_post(pt_sem_t *sem);发送信号量
PT_SEM_WAIT_BLOCK(pt, s, ms);等待信号量,单位毫秒s
PT_SEM_WAIT_YEILD(pt, s, cnt);等待信号量,单位轮询次数
  • pt_event_extern.h 主要提供以下接口
事件旗标接口名称含义
void pt_event_init(pt_event_t *event);初始化事件旗标量
void pt_event_set_bit(pt_event_t *event, uint32_t bit_mark);事件旗标发送信号
int pt_event_clear_bit(pt_event_t *event, uint32_t bit_mark);事件旗标清空信号
PT_EVNET_WAIT_BLOCK(pt, e, ms);等待事件变真,超时单位毫秒
PT_EVNET_WAIT_YEILD(pt, e, cnt);等待事件变真,超时单位轮询次数
  • pt_queue_extern.h 主要提供以下接口
事件旗标接口名称含义
void pt_queue_init(pt_queue_t *queue, uint8_t *addr, uint16_t memery_size, uint16_t item_size);初始化消息队列
int pt_queue_write(pt_queue_t *queue, void *item);写消息
int pt_queue_read(pt_queue_t *queue, void *item);读消息
PT_QUEUE_WRITE_BLOCK(pt, q, item, ms)等待写入消息成功,超时单位毫秒
PT_QUEUE_READ_BLOCK(pt, q, item, ms)等待读取消息成功,超时单位毫秒
PT_QUEUE_WRITE_YEILD(pt, q, item, cnt)等待写入消息成功,超时单位轮询次数
PT_QUEUE_READ_BLOCK(pt, q, item, cnt)等待读取消息成功,超时单位轮询次数
  • pt_box_extern.h 主要提供以下接口
事件旗标接口名称含义
void pt_box_init(pt_box_t *box);初始化广播邮箱
void pt_box_get_msg(pt_box_t *box, void **msg)获取广播邮箱里面的消息
PT_BOX_SEND_BLOCK(pt, b, target, msg, ms)等待发送消息成功,超时单位毫秒
PT_BOX_SEND_YIELD(pt, b, target, msg, cnt);等待发送消息成功,超时单位轮询次数
PT_BOX_ACCEPT_BLOCK(pt, b, cb, para, ms);等待接受消息成功,超时单位毫秒
PT_BOX_ACCEPT_YEILD(pt, b, cb, para, cnt);等待接受消息成功,超时单位轮询次数

PTOS 优缺点分析

由于PTOS的调度原理使用了Protothreads,所以PTOS也继承了Protothreads的优点和缺点。以下对其优点和缺点进行分析

优点一:OS移植方便

PTOS 唯一使用硬件相关的只有System Tick,我们只需要外部实现System Tick的就可以成功移植PTOS!!!

优点二:OS对MCU资源要求低

PTOS的移植(不开monitor,什么都不做) 需要ram 44(4+4+4+4+28)字节, rom 1156 (80+108+544+424)。后面新增加一个thread,仅需要开销28字节,若新增软件定时器需要8字节。
在这里插入图片描述

缺点一:无堆栈

PTOS是无堆栈的操作系统,所有线程公用一个堆(PTOS使用堆容易出错,线程内部不建议使用),且线程无栈。无堆低资源的MCU影响不大,但线程无栈,意味着局部变量在线程调度的时候会释放,局部变量的使用变得谨慎。我们只需要在使用的时候遵循以下原则,也可以在代码编程时进行规避

  1. 局部变量在程序调度之后不要使用,如果需要使用调度之前的变量,在函数内使用static变量
  2. 引发任务调度的函数一般都是大写的宏
  3. 线程内部不要使用malloc和free,如果确实需要使用,可参考以下方式
{
	static uint8_t *prt = NULL;
	static uint8_t prt_size = 0;
	if(prt == NULL && prt_size != size)
	{
		prt = malloc(size);
		prt_size = size;
	}
	....
	if(prt)
	{
		free(prt);
		prt= NULL;
		prt_size = 0;
	}
}

缺点二:非实时

PTOS不是实时系统,所有线程同属一个有限等级。每个线程需要自己主动释放出cpu使用权限,否则其他线程将会饿死。用户创建的任务,都会影响实时性的高低。但PTOS作为一个低资源的MCU的OS来说,线程数目本来不多,如果用户合理遵循不使用硬延迟的方式(系统提供了PT_SLEEP_MS函数),都可以满足用户的使用需求的.

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值