时间片轮询
所谓时间片轮询就是将时间分时,分别分配给不同的任务去执行任务,这个被任务分走的时间就叫做时间片。
时间片轮询系统中很重要的一点就是时间片的长度,当时间片的长度过小时,例如设置为20ms,因为在任务切换时,需要保存上下文,这个是需要花费时间的,假设花费为5ms,此时CPU20%(5/20+5)的时间花浪费在了管理开销上(网上查的,这里还不太明白为什么会说这是浪费?这个不是必须存在的吗?无论时间片的长度长还是短,这不是都得存在的?如果有知道的人可以指导一下,后续更新)
当时间片设置为500ms,这个时候CPU管理上下文的时间占用率只有1%了,但是当你的系统需要运行多个(7/8个或者以上的时候),就会出现任务时间处理过长而无法及时响应了。
所以可以得出:时间片过短会降低效率,而设置的太长又会导致实时性较差,所以时间片应该设置在合理的范围内。
时间片轮询实际上就是一个通过一个基准时钟去实现定时去分别调用不同任务,如5ms任务就是每隔5ms调用一次,这种轮询方式一定要注意任务的执行时间一定要短小精悍,因为当你的任务执行时间大于时间片的时候,在你退出任务调度(定时器中断之后)会接着执行上一次未完成的任务而影响任务调度,所以执行任务的时间一定要小于时间片的长度,否则会影响其他任务的调度。
具体实现
任务结构体
typedef struct
{
uint8_t enable_flag; // 任务使能标志,0不需要运行,1需要运行
uint16_t timer; // 还差多少时间就需要调度这个任务
uint8_t run; // 任务是否就绪,0未就绪,1就绪态
uint16_t interval_time; // 任务运行的间隔时间,即每隔多久调度一次
void (*task)(void); // ָ任务回调函数,即要运行的任务函数
}TaskStruct;
任务调度器实现(在中断中进行任务的调度)
void task_schedule(void)//任务调度函数
{
for (uint8_t i=0; i<TASKS_MAX; i++) // 逐个任务时间处理,TASKS_MAX有多少个任务
{
if (mytask_list[i].timer) // 时间不为0
{
mytask_list[i].timer--; // 减去一个节拍
if (mytask_list[i].timer == 0) // 时间减完了
{
mytask_list[i].timer = mytask_list[i].interval_time; // 恢复计时器值,从新下一次
mytask_list[i].run = 1; // 任务可以运行
}
}
}
}
任务处理函数
void task_process(void)//任务执行函数
{
for (uint8_t i=0; i<TASKS_MAX; i++) // 逐个任务时间处理
{
if(mytask_list[i].enable_flag) //是否使能任务,即任务是否可以被执行
{
if (mytask_list[i].run) // 时间不为0
{
mytask_list[i].run = 0; // 标志清0
mytask_list[i].mytask(); // 运行任务
}
}
}
}
任务列表
static TaskStruct task_list[] =
{
{0, 60, 60, task1}, // 任务1
{0, 20, 20, task2}, // 任务2
{0, 30, 30, task3}, // 任务3
// 添加任务。。。。
};
任务优先级,时间间隔越小,优先级越高(数字越小)
typedef enum _TASK_PRIORITY
{
TASK1, // 最先调度
TASK2, // 其次
TASK3, // 随后
// 添加任务。。。。
TASKS_MAX // 总的可供分配的定时任务数目
} TASK_PRIORITY;
为什么说数字越低优先级越高呢?因为在调度时是顺序执行的
以上纯属个人见解,有误之处还请大家指正。