软件架构之时间片轮询
时间片轮询法是一种比较简单易用的系统架构之一,它对于系统中的任务调度算法是分时处理。核心思路是把 CPU 的时间分时给各个任务使用。我们常用的定时方法是定时器,把调度器放在定时中,可以简单的实现时间片轮询法。
废话不多,直接上代码。
//***软件架构之时间片轮询***//
#include<stdio.h>
#define TASK_NUM (3) //任务数为3,有3个任务会使用此定时器定时
//任务数可以直接给定或可以根据任务数组长度去判断
//***声明任务结构体***//
typedef struct _TaskStruct
{
int run_flag; //任务执行标志位
int timer; //定时器当前值
int interval_time; //任务运行的时间间隔,隔多久调度一次,定时器的值
int (*task)(); //任务回调函数
}TaskStruct;
//***任务函数***//
int task1 () //任务1
{
printf("this is task1.\n");
return 0;
}
int task2 () //任务2
{
printf("this is task2.\n");
return 0;
}
int task3 () //任务3
{
printf("this is task3.\n");
return 0;
}
//***定义任务结构体***//
static TaskStruct TaskComps[]=
{
{0,4,4,task1}, //任务1
{0,2,2,task2}, //任务2
{0,3,3,task3}, //任务3
//添加任务
};
//***任务标志位处理***//
void task_flag(void)
{
int i ;
for (i=0;i<TASK_NUM;i++) //逐个执行3任务
{
if (TaskComps[i].timer) //定时器值不为0,即定时器时间未到
{
TaskComps[i].timer--; //定时器值-1
if (TaskComps[i].timer == 0) //定时器值为0,定时时间到
{
TaskComps[i].timer = TaskComps[i].interval_time; //恢复定时器初值,以便重新开始计数
TaskComps[i].run_flag = 1; //标志位置1,开始执行任务i
printf(" RUN_FLAG %d \n",i+1);
}
}
}
}
//***任务执行***//
void task_process(void)
{
int i;
for (i=0;i<TASK_NUM;i++) //逐个执行3任务
{
if (TaskComps[i].run_flag) //标志位为1,任务执行
{
TaskComps[i].task(); //执行任务
TaskComps[i].run_flag = 0; //标志位清零
}
}
}
//***主函数***//
int main(void)
{
//一般需要先对用到的模块进行初始化,然后开始任务的轮询
while(1)
{
printf("begin.\n");
task_flag(); //此处必须把标志位处理的函数一起放进while循环里,否则程序不能正常运行。
//猜想原因是若将其不放进来,run_flag一直是0,task_process()也就无法进行。
task_process();
}
}
程序某次的运行结果如下。可以看到,每次运行时,程序是先将run_flag置1,然后再执行任务,这没什么问题;但是,程序并不是刷新一个run_flag之后就执行相对应的任务,而是将所有run_flag全部刷新之后,再依次执行相对应的任务。
begin.
RUN_FLAG 1
RUN_FLAG 2
RUN_FLAG 3
this is task1.
this is task2.
this is task3.
begin.
begin.
RUN_FLAG 2
this is task2.
begin.
RUN_FLAG 3
this is task3.
begin.
RUN_FLAG 1
RUN_FLAG 2
this is task1.
this is task2.
begin.
begin.
RUN_FLAG 2
RUN_FLAG 3
this is task2.
this is task3.
begin.
begin.
RUN_FLAG 1
RUN_FLAG 2
this is task1.
this is task2.
begin.
RUN_FLAG 3
this is task3.
begin.
RUN_FLAG 2
this is task2.
另一方面,仔细看下面的结果,我们很容易发现,程序并不是每次都按照任务1,任务2,任务3这样的顺序全部执行的,有时候一个周期内只执行任务2,或者任务3,或者执行两个任务,并不是每次都3个任务顺序执行。这是因为每个任务的执行时间不同,我们由在定义任务结构体时设置的参数决定的,是可以根据任务的需要自行设定的。
需要注意的是,时间片轮询里的任务应该尽可能短小精悍,若执行任务时间太长,会导致任务还没执行完系统就已经刷到下一个任务去了。
//***定义任务结构体***//
static TaskStruct TaskComps[]=
{
{0,4,4,task1}, //任务1
{0,2,2,task2}, //任务2
{0,3,3,task3}, //任务3
//添加任务
};