niyade 发表于 2018-5-2 16:29

关于时间片轮询框架的理解

最近接触了时间片轮询的代码程序,估计很多大神都知道,但为了问题明确,我还是把这个框架说一下,免得产生误解。
首先定义一个定时器产生一个时基中断。然后定义一个任务结构体,包括运行标记,轮询时间,任务函数指针等。定时器中断中通过for循环每个任务的时间减一个节拍,直到减为0,将运行标志位置一。然后主循环中同样通过for循环判断运行标志位是否为1,如果是则运行。具体是哪种框架,我还是放个链接吧,以确保百分百能明白我的问题。(我没权限加网址,看楼下能不能回复)
但是我对此有一个疑问。就是我之前设计程序时都同样初始化一个定时器时基,根据任务有啥Flag_10ms, Flag_20ms等时间标志,时间到了就在中断里面讲此标志置1.然后主循环里用if判断标志是否为1,是的话就执行功能函数,如下:
int main(void)
{
while(1)
{
    if(true==Flag_10ms)
   {
      Flag_10ms =false;
      Function1();
   }

    if(true==Flag_20ms)
   {
      Flag_20ms =false;
      Function2();
   }
   ..........
}
return 0;
}
我就觉得这两种都是一个原理啊,但为什么别人都推崇第一种呢。所以最终我有两个问题求大家解决一下:
1:这两种框架最终是不是一个原理?实现的功能效果完全一样?
2:为什么大家都比较推崇第一种,他有什么优势?是不是框架清晰,易于管理?






niyade 发表于 2018-5-2 16:30

也不能发网址

WANGY2000 发表于 2018-5-3 07:33

不错,日积月累,共同提高。

ayb_ice 发表于 2018-5-3 09:49

没有本质区别,第一种就是规范点,可以通过初始化设定,运行过程中也可以改变,通用性强点

niyade 发表于 2018-5-3 10:23

ayb_ice 发表于 2018-5-3 09:49
没有本质区别,第一种就是规范点,可以通过初始化设定,运行过程中也可以改变,通用性强点 ...

嗯,理解

菜鸟同学 发表于 2018-5-3 18:43

时间片和OS都是 合理的分配CPU时间。

elife 发表于 2018-5-4 20:49

楼主,你的程序框架上如果一个任务运行超过了20ms运行时间,是会丢掉下一个任务的一次运行的。不能做到实时任务。做到实时任务是要时间片一结束,立即调度到下一个任务执行。

7456 发表于 2018-5-4 23:54

第一种叫时间片,第二种叫轮询式,需要程序能主动退出任务,早期的WIN3.2和苹果的iOS都是这样做的,各有优缺点。

老陆693 发表于 2018-5-6 16:50

本帖最后由 老陆693 于 2018-5-6 16:59 编辑

给楼主推荐一本书:《时间触发嵌入式系统设计模式》//定义一个结构
typedef struct
{
void (*pTask)(void);      //函数指针
unsigned intsDelay;   //休眠时间
unsigned intsPeriod;    //休眠时标
unsigned char sRunMe;   //运行时
}sTask;


sTask SCH_tasks_G;
unsigned char Error_code_G;


//使用单片机一个定时器做为Systemtick,这段代码放在定里器中断里面
定时器中断函数(void)
{
unsigned char uc_taskPoll;
//调试器任务查询
for(uc_taskPoll=0; uc_taskPoll<SCH_MAX_TASKS; ++uc_taskPoll)
    {
      if(SCH_tasks_G.pTask)            //任务有分配
      {
          if(SCH_tasks_G.sDelay == 0)    //有任务要开始
            {
            SCH_tasks_G.sRunMe += 1;
            if(SCH_tasks_G.sPeriod)
                SCH_tasks_G.sDelay = SCH_tasks_G.sPeriod;
            }
            else
            SCH_tasks_G.sDelay -= 1;
      }
    }
}

//任务调度
void SCH_Disptch_Tasks(void)
{
unsigned char Index;

while(1){
for(Index=0; Index<SCH_MAX_TASKS; ++Index)
    {
      if(SCH_tasks_G.sRunMe > 0)
      {
          (*SCH_tasks_G.pTask)();      //执行任务
          SCH_tasks_G.sRunMe -= 1;       //清除任务需要执行的标志   

          if(SCH_tasks_G.sPeriod == 0)   //如果这是个“单次”任务,将它从队列中删除   
            SCH_Delete_Task(Index);   
      }   
      //空闲任务
      //SCH_Report_Status();                        //报告系统状况   
      //SCH_Go_To_Sleep();                            //进入体眠
    }
}

//添加任务
//Delay:第一次运行延时,为0立即执行,以后执行按PERIOD循环时间
//单次任务将PERIOD设置为0
unsigned char SCH_Add_Task(void (* pFunction)(),
                           unsigned int Delay,
                           unsigned int PERIOD)
{
unsigned char Index = 0;

while((SCH_tasks_G.pTask != 0) && (Index < SCH_MAX_TASKS))       //找一个任务空隙放置任务
    ++ Index;
if(Index == SCH_MAX_TASKS)                              //任务列队已满
    {
      Error_code_G = ERROR_SCH_TOO_MANY_TASKS;
      return SCH_MAX_TASKS;
    }
SCH_tasks_G.pTask = pFunction;
SCH_tasks_G.sDelay = Delay;
SCH_tasks_G.sPeriod = PERIOD;
SCH_tasks_G.sRunMe = 0;
return Index;
}

//删除任务
unsigned char SCH_Delete_Task(unsigned char TASK_INDEX)   
{   
unsigned char Return_code;   
if(SCH_tasks_G.pTask == 0)   
    {   
      //这里没有任务。。。设置全局错误变量   
      Error_code_G = ERROR_SCH_CANOT_DELETE_TASK;   
      Return_code = RETURN_ERROR;//返回错误代码   
    }   
    else
      {
      Return_code = RETURN_NORMAL;   
      //删除任务   
      SCH_tasks_G.pTask = 0x0000;   
      SCH_tasks_G.sDelay = 0;   
      SCH_tasks_G.sPeriod = 0;   
      SCH_tasks_G.sRunMe = 0;   
      }
return Return_code;   
}   


PS:上面代码仅供参考,涉及中断保护没有给出,随便使用,没有版权,后果自负。
这种结构易于维护,代码可读性高,写程序的时候注意一下时间片和执行时间,可以确定程序运行时间。
再有就是常常需要休眠降低功耗的场合灰常适用。

pmw_56 发表于 2018-5-14 11:52

老陆693 发表于 2018-5-6 16:50
给楼主推荐一本书:《时间触发嵌入式系统设计模式》//定义一个结构
typedef struct
{


你这个任务的调度时间复杂度是 O(N) ,如果用查表优先级 O(C) ,常数C固定的,调度是时间固定,像uC/OS 一样的,可以搞16个任务优先级表来查询。

天命风流 发表于 2018-5-14 15:19

说的还不错

armcortex 发表于 2023-1-8 20:28

深入理解不错。
页: [1]
查看完整版本: 关于时间片轮询框架的理解