经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C 语言 » 查看文章
时间片轮询法
来源:cnblogs  作者:suanite  时间:2018/12/24 10:36:55  对本文有异议

时间片轮询法

时间片轮询法是一种比较简单易用的系统架构之一,它对于系统中的任务调度算法是分时处理。核心思路是把 CPU 的时间分时给各个任务使用。我们常用的定时方法是定时器,把调度器放在定时中,可以简单的实现时间片轮询法。

需要注意的是,这种方法的前提是执行的 每个任务都是短小精悍的,要不然一个任务执行的时间过长,大于其它任务设置的时间片值,那其它任务就无法保证按它预设的时间片来执行。

尤其需要注意任务中延时的使用,可能会产生不可预料的结果。如果任务内部需要延时的时候,或者说单个任务过长,需要保存任务执行到一半的状态,建议使用状态机切割长任务。

时间片轮询法架构

一个时间片轮询应用程序的架构是非常简单的,包括一个任务结构体,一个中断处理函数,一个轮询执行任务函数。

设计一个结构体:

  1. // 任务结构
  2. typedef struct {
  3. uint8_t task_id; // 任务 ID
  4. uint16_t task_interval; // 任务运行间隔时间
  5. void (*task_entry)(void); // 要运行的任务
  6. volatile uint16_t task_tick_ms; // 计时器
  7. }task_info_t;

定时器复用和中断处理

定时器可以是任意的定时器,这里采用系统滴答定时器 (systick) 来定时。systick 的配置就不细讲,假设定时器的定时中断为 10ms(可以自行设定,中断过于频繁效率就低,中断太长,实时性差)。

timing_task_tick 函数就相当于中断服务函数,需要在定时器的中断服务函数中调用此函数。

  1. // 为每个任务计时,每次中断加 10ms
  2. void timing_task_tick(void)
  3. {
  4. uint8_t task_index = 0;
  5. while (task_index < ARRAY_SIZE(timing_task_array))
  6. {
  7. timing_task_array[task_index].task_tick_ms += CONFIG_SYSTEM_TICK_PERIOD_MS; // 每次加一个 systick 周期,即 10ms
  8. task_index++;
  9. }
  10. }

时间片轮询实例

下面我就就说说怎样应用吧,假设我们有三个任务:时钟显示,按键扫描,和工作状态显示。

定义一个上面定义的那种结构体数组

  1. // 计算任务个数
  2. #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
  3. // 定义了 3 个任务
  4. static task_info_t timing_task_array[] =
  5. {
  6. {0, 100, task_disp_clock_running, 0}, // 显示时钟
  7. {1, 20, task_scan_key_running, 0}, // 按键扫描
  8. {2, 30, task_disp_ws_running, 0}, // 工作状态显示
  9. };

在定义变量时,我们已经初始化了值,这些值的初始化,非常重要,跟具体的执行时间优先级等都有关系,这个需要自己掌握。

  1. 大概意思是,我们有三个任务,每 1s 执行一下时钟显示,因为我们的时钟最小单位是 1s,所以在秒变化后才显示一次就够了。

  2. 由于按键在按下时会参数抖动,而我们知道一般按键的抖动大概是 20ms,那么我们在顺序执行的函数中一般是延伸 20ms,而这里我们每 20ms 扫描一次,是非常不错的出来,即达到了消抖的目的,也不会漏掉按键输入。

  3. 为了能够显示按键后的其他提示和工作界面,我们这里设计每 30ms 显示一次,如果你觉得反应慢了,你可以让这些值小一点。后面的名称是对应的函数名,你必须在应用程序中编写这函数名称和这三个一样的任务。

编写任务函数

  1. //Description : 显示任务
  2. void task_disp_clock_running(void)
  3. {
  4. }
  5. //Description : 扫描任务
  6. void task_scan_key_running(void)
  7. {
  8. }
  9. //Description : 工作状态显示
  10. void task_disp_ws_running(void)
  11. {
  12. }

任务处理

  1. // 任务计划表,轮询执行任务
  2. void timing_task_scheduler(void)
  3. {
  4. uint8_t task_index = 0;
  5. while (1)
  6. {
  7. for (task_index = 0 ; task_index < ARRAY_SIZE(timing_task_array); task_index++)
  8. {
  9. if (timing_task_array[task_index].task_tick_ms >= timing_task_array[task_index].task_interval)
  10. {
  11. timing_task_array[task_index].task_tick_ms = 0;
  12. timing_task_array[task_index].task_entry();
  13. }
  14. }
  15. }
  16. }

程序陷入死循环,依次判断每个任务是否符合执行要求。如果是,则执行相应的任务函数;否则等待计时。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号