1. 任务函数
- 通常运行在死循环,不会退出。
- 不允许以任何方式从函数中返回,不能执行到函数末尾。
- 任务不再需要时,可以显示将其删除。
void ATaskFunction(void *pvParameters)
{
int iVariableExample = 0;
for(;;)
{
//任务功能代码
}
vTaskDelete(NULL);
}
2. 创建任务: xTaskCreate
- configMINIMAL_STACK_SIZE 决定空闲任务的栈空间大小。
- vTaskStartScheduler() 启动调度器,任务开始执行。
portBase_TYPE xTaskCreate(
pdTask_CODE pvTaskCode, //task function
const signed portCHAR * const pcName, //task pcName
unsigned portSHORT usStackDepth, //stack size in word
void *pvParameters, // task function input pvParameter
unsigned portBase_TYPE uxPriority, //task Priority
xTaskHandle *pxCreatedTask //Task xTaskHandle);
3. 任务优先级
- 优先级的范围从最低0到最高优先级(configMAX_PRIORITIES - 1)。
- 调度器保证总是在所有可运行的任务中选择具有最高优先级的任务,并使其进入运行态。
- 如果被选中的优先级上不止一个任务,调度器会让这些任务按时间片轮流执行。
- 时间片的长度通过心跳中断频率进行设定, configTick_RATE_HZ
4. 任务状态
阻塞状态
任务进入阻塞等待的事件有:
定时事件(延迟到期, 绝对时间到点),
同步事件: 队列,二值信号量,互斥信号量,互斥量都可以来实现同步事件.
vTaskDelay(portTickType xTicksToDelay) //延迟到期
void vTaskDelyUntil(poartTickType *pxPreviousWakeTime, portTickType xTimeIncreament)
挂起状态
处于挂起态的任务对调度器是不可见的。进入和退出该状态的API:
vTaskSuspend()
vTaskResume()
vTaskResumeFromeISR()
就绪态
运行态
5. 空闲任务和空闲任务钩子函数
- 空闲任务优先级最低(0)
- 钩子函数执行低优先级,后台或需要不停处理的功能代码;测试系统处理裕量;将处理器配置到低功耗模式。
- 钩子函数实现限制,绝不能阻塞或挂起,否则可能导致没有任务进入运行态;如果应用程序用到了vTaskDelete(),需要空闲任务负责回收内核资源。如果空闲任务一直运行在钩子函数中,则无法进行回收工作,因此钩子函数需要尽快返回。
6. 改变任务优先级
void vTaskPrioritySet(XTaskhandle pxTask unsigned portBase_TYPE uxNewPriority)
unsigned portBase_TYPE uxTaskPriorityGet(xTaskHandle)
7. 删除任务
空闲任务回收内核分配被删除任务的内存资源,因此使用vTaskDelete的任务不能饿死空闲任务。
被删除任务自身占有内存资源需要应用程序自己显示释放。
void vTaskDelete(xTaskHandle pxTaskToDelete)
8. 调度算法
固定优先级抢占式调度
- 每个任务赋予一个优先级
- 每个任务都可以存在于一个或多个状态
- 在任何时候都只有一个任务可以处于运行状态
- 调度器总是在所有处于就绪态的任务中选择具有最高优先级的任务来执行
- 任务可以处于阻塞状态,等待时间事件或同步事件触发唤醒
单调速率调度(Rate Monotonic Scheduling, RMS)
- 根据任务周期性执行的速率分配已给唯一的优先级。
- 执行频率越高,优先级越高;反之,优先级越低
协作式调度
- 只可能在运行态的任务进入阻塞或显示调用taskYIELD(),才会进行行下文切换
- 任务不会被抢占,相同优先级的任务之间不会自动共享处理器时间
混合调度方案
中断服务例程显示地进行上下文切换,从而允许同步事件产生抢占,时间事件不能抢占。
- 这样得到了一个没有时间片机制的抢占式系统