1

1. 任务管理

任务就是线程的另一种说法

1.1 实时性

  • 软实时
    软件保证线程的切换在一个恰当的时间范围内
  • 硬实时
    必须在给定的时间限制内完成,安全气囊是一个明显的例子

大多数嵌入式要满足软硬实时

1.2 任务函数

void ATaskFunction(void *pvParameters);

FreeRTOS不允许线程自行结束——绝不能有return,如果一个任务不需要了,需要显式的将其删除。

  • 为什么不能直接return?
    FreeRTOS给每个任务会分配其自己的栈空间,建立一个任务的堆栈结构,这时PC指针指向任务函数的初始地址,FreeRTOS把他设为0,也就是说,函数一返回,就会跳到0地址,导致硬件错误,所以不能直接返回。

任务函数可以有属于自己的栈空间,以及属于自己的自动变量(栈变量)
典型的任务函数结构:

void ATaskFunction(void *pvParameters)
{
    int iVariableExample = 0;
    
    for ( ; ; ) {
    
    }
    
    vTaskDelete(NULL);
}

1.3 顶层任务状态

简单划分为运行态和非运行态
处于运行态,处理器就执行它的代码,处于非运行态,任务休眠,所有的状态都会被妥善保存,等待下一次恢复。

1.4 优先级

优先级号0表示最低优先级。调度器总是选择具有最高优先级的可运行任务来执行。比如两个任务,优先级分别是1和2,则调度时2会被执行,1不会被执行,这种情况成为任务1的执行时间被任务2饿死了。

对于ARM M3来说,0表示最高优先级,数值越大,优先级越低

tick的概念
处于任务运行间的系统中断,成为tick,是周期性的,用来进行任务的调度。
红点处就是tick产生。
clipboard.png

1.5 非运行态

  • 挂起
    处于挂起状态的任务对于调度器而言是不可见的。
  • 阻塞
    任务一直在等待某个事件
  • 就绪
    准备运行,尚未运行

clipboard.png

1.6 空闲任务和hook函数

  • 空闲任务
    在大部分任务处于阻塞态的时候,这种状态下所有的任务都不可运行,但处理器总是需要代码来执行,所以调度器会自动创建一个空闲任务,空闲任务通常是一个非常短小的循环,用于最低的优先级,可以被其他任务抢占。
  • 空闲任务钩子函数
  1. or call-back

空闲任务每循环一次,就会自动调用一次hook

  • 绝对不能阻塞或挂起
  • hook函数要短小,能够尽量返回,因为空闲函数还负责任务被删除后,回收内核资源,所以空闲任务一直运行在钩子函数中,则无法进行回收工作。

调度算法——简述

  • 优先级抢占式调度

    • 每个任务都赋予一个优先级
    • 每个任务都可以存在于一个或多个状态
    • 在任何时候都只有一个任务可以处于运行状态
    • 调度器总是在所有处于就绪态的任务中选择具有最高优先级的任务来执行
  • 协作式调度
    采用一个纯粹的协作式调度器,只可能在运行态任务进入阻塞态或是运行态任务显式调用taskYIELD()时,才会进行上下文切换,任务永远不会被抢占,具有相同优先级的任务也不会自动共享处理器时间。协作式调度的这种工作方式虽然比较简单,但可能回导致系统响应不够快。

所以混合调度方案也是可行的。

待续。


shlin
17 声望4 粉丝