[uCOS/RTOS]

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

[复制链接]
3287|11
手机看帖
扫描二维码
随时随地手机跟帖
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 int  sDelay;     //休眠时间  
  unsigned int  sPeriod;    //休眠时标  
  unsigned char sRunMe;     //运行时  
}sTask;


sTask SCH_tasks_G[SCH_MAX_TASKS];
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[uc_taskPoll].pTask)              //任务有分配  
        {
          if(SCH_tasks_G[uc_taskPoll].sDelay == 0)    //有任务要开始  
            {
              SCH_tasks_G[uc_taskPoll].sRunMe += 1;
              if(SCH_tasks_G[uc_taskPoll].sPeriod)
                SCH_tasks_G[uc_taskPoll].sDelay = SCH_tasks_G[uc_taskPoll].sPeriod;  
            }  
            else
              SCH_tasks_G[uc_taskPoll].sDelay -= 1;
        }  
    }
}

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

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

          if(SCH_tasks_G[Index].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[Index].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[Index].pTask = pFunction;
  SCH_tasks_G[Index].sDelay = Delay;
  SCH_tasks_G[Index].sPeriod = PERIOD;
  SCH_tasks_G[Index].sRunMe = 0;
  return Index;
}

//删除任务
unsigned char SCH_Delete_Task(unsigned char TASK_INDEX)   
{   
  unsigned char Return_code;   
  if(SCH_tasks_G[TASK_INDEX].pTask == 0)   
    {   
      //这里没有任务。。。设置全局错误变量   
      Error_code_G = ERROR_SCH_CANOT_DELETE_TASK;   
      Return_code = RETURN_ERROR;//返回错误代码   
    }   
    else  
      {
        Return_code = RETURN_NORMAL;   
        //删除任务   
        SCH_tasks_G[TASK_INDEX].pTask = 0x0000;   
        SCH_tasks_G[TASK_INDEX].sDelay = 0;   
        SCH_tasks_G[TASK_INDEX].sPeriod = 0;   
        SCH_tasks_G[TASK_INDEX].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 | 显示全部楼层
深入理解不错。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

26

主题

172

帖子

2

粉丝