任务状态与调度

  • 任务状态:在任务创建和删除的基础上添加了任务的暂停和恢复
  • 调度

目录

一、任务状态(Freertos)

1、任务的状态(Freertos)

2、借助音乐播放器程序剖析状态

在创建任务函数中:

新创建的3个任务属于ready状态​编辑

音乐播放任务的创建和删除在默认任务里,其状态剖析如下:

3、添加音乐暂停和恢复功能

在函数中传入句柄就实现任务状态的暂停与恢复

二、任务管理

1、调度:

结论:

2、任务优先级管理举例

(1)任务组成的链表放在数组中

(2) 启动内核时在任务调度器中会创建优先级为0的空闲任务

(3)链表中的指针pxCurrent

(4)任务调用

1/第一次调度:

2/第二个时钟周期

*在默认任务中创建了优先级更高的任务

按下暂停键:把任务放入suspended链表

按下播放键:把任务从suspended链表放回ready链表 

系统时钟Tick中断:

Q:各个任务切换任务状态保存在TCB结构体?

Q:任务和线程的关系

一、任务状态(Freertos)

1、任务的状态(Freertos)

  1. 就绪状态(ready):可以随时执行(只要有机会切换,就可以变为running状态)
  2. 执行状态(running):正在执行(被调度出去后变为ready状态)(调用到阻塞函数会切换到阻塞状态)
  3. 阻塞状态(Blocked):等待某些事件
  4.  暂停状态(Suspended):暂停当前工作。(自己running时,调用函数;别人runnning,自己ready或block时,别人调用函数

2、借助音乐播放器程序剖析状态

main.c

初始化内核

创建任务

启动调度器

在创建任务函数中:

新创建的3个任务属于ready状态
音乐播放任务的创建和删除在默认任务里,其状态剖析如下:
  • 音乐播放的优先级高,所以先执行,处于running状态;
  • 音乐播放函数中的延迟函数为阻塞函数,处于Blocked状态(等待其他任务执行);
  • 当时间到之后,就会被唤醒,进入ready就绪状态,在能运行的时候变为running状态

PS:声音播放函数 中的阻塞函数

PS:阻塞函数:等待某些时间或等待某些数据————同步与互斥

3、添加音乐暂停和恢复功能

在函数中传入句柄就实现任务状态的暂停与恢复

resume后的运行和running不是一回事?

答:继续执行任务(该任务可能在阻塞态可能在运行态)

PS:暂停的时候要停止蜂鸣器,否则蜂鸣器保持一个音调

二、任务管理

1、调度:

  • 相同优先级 的任务轮流运行
  • 最高优先级 的任务先运行

结论:

  1. 只要有高优先级的未执行完,低优先级的无法运行
  2. 一旦高优先级任务就绪,马上运行高优先级
  3. 若最高优先级的任务有多个,他们轮流运行

在代码中通过链表进行任务的管理

2、任务优先级管理举例

(1)任务组成的链表放在数组中

最高优先级 的个数

数组中 的56项目,每一项都是一个链表 

第n项放的是: 优先级为n的处于ready状态的任务

(2) 启动内核时在任务调度器中会创建优先级为0的空闲任务

启动内核

任务调度器

创建空闲任务

(3)链表中的指针pxCurrent

创建任务函数中把任务加入就绪链表

 在就绪链表函数中有优先级判断

一开始没有其他任务。所以指向第一个任务;

当创建同级任务时,pxCurrent指向同级的新任务;

当执行内核启动函数时,因空闲任务的优先级较低,故pxCurrent不变

当启动调度器时,从pxCurrent开始,先运行最后创建的任务

(4)任务调用

执行完任务3重新发起调度

1/第一次调度:

每1ms产生一次时钟中断 

调度(遍历ReadyList),找到第一个非空的链表

2/第二个时钟周期

TICK中断:运行1ms后会再次触发Tick中断,计数值累加,再次发起调度

调度机制:再次从上到下遍历链表,找出非空的链表中下一个要执行的任务

*在默认任务中创建了优先级更高的任务

  1. 任务在创建后为就绪状态,因优先级最高,所以打断本时钟周期内的其他任务,优先执行该任务;
  2. 当执行到延时函数(延时2s)时,为就绪状态,会被从Ready列表中删除,移到某一个DelayTaskList;
  3. 当执行到延时函数时会触发调度,依据记录index取出下一个任务来运行
  4. 在两次时钟中断后,会发起一个调度,在去遍历就绪链表前,先到Delay链表,判断Delay链表中的任务是否可恢复,到时间的话就把这个任务放入就绪链表

按下暂停键:把任务放入suspended链表

按下播放键:把任务从suspended链表放回ready链表 

系统时钟Tick中断:

  1. 累加计数cnt++
  2. DelayedTaskList中处于阻塞态的任务是否可以恢复(是否到时)为就绪态
  3. 遍历就绪链表

三、空闲任务

作用:

释放被删除的任务的内存

避免调度时其他任务阻塞的情况

1、任务的函数不是死循环,所有任务都无法再次执行,(将会返回错误函数)

1、在错误函数中会关闭Tick中断,导致任务无法切换,之后陷入错误函数的死循环

2、如果任务 不是死循环会退出的代码

任务创建函数调用初始化栈

 {

在初始化栈时伪造好LR寄存器的值(错误函数)(在函数执行完要返回到LR寄存器所指示的位置)

{ 

2、任务如何结束

 自己结束任务:

任务结束后的清除工作:

在创建任务B时候,动态的分配了内存、结构体、栈

在结束任务时候要释放TCB结构体、栈

若是自己结束任务,需要空闲任务来清楚,但若更高优先级的任务都是就绪态,空闲任务无法获取CPU资源执行操作,可能会因无法回收造成内存不足

良好的编程习惯:

  1. 事件驱动(避免一致死循环占用CPU)(比如按下按键才就绪,没按按键就阻塞)
  2. 休眠时不要用死循环,建议替换为阻塞函数

空闲任务的函数

main.c

{启动调度器

{启动调度器

{创建任务

{空闲任务的函数

检查等待中止(自杀)的任务

钩子函数?

四、让当前任务放弃调度的delay函数

1 、两个 Delay 函数


⚫ vTaskDelay:至少等待指定个数的 Tick Interrupt 才能变为就绪状态
⚫ vTaskDelayUntil:等待到指定的绝对时刻,才能变为就绪态。

void vTaskDelay( const TickType_t xTicksToDelay ); /* xTicksToDelay: 等待多少给Tick */
/* pxPreviousWakeTime: 上一次被唤醒的时间
* xTimeIncrement: 要阻塞到(pxPreviousWakeTime + xTimeIncrement)
* 单位都是Tick Count
*/
BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime,
const TickType_t xTimeIncrement );//起始时间、增量时间

vTaskDelay:不能保证每次开始的时间间隔是周期性的,只能保证阻塞的时间大于等于5ms

vTaskDelayUntil:保证每次开始的时间间隔是周期性

到时间后记录被唤醒的时间T2,并让任务进入就绪态

函数实现 

传入起始时间 

while{

do_sth();//1ms,5ms,10ms

xTaskDelayUntil(&preTime ,15);//到preTime +15时进入就绪状态,并修改preTime的时间;

}

PS:获取系统当前时间

Q:各个任务切换任务状态保存在TCB结构体?

Q:任务和线程的关系

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值