3. 时间片轮转调度

任务目标

在 VxWorks 中创建两个同优先级任务,通过配置时间片轮转调度(Round-Robin),使两个任务按固定时间片交替占用 CPU,从而验证同优先级任务间的公平调度行为。

核心原理

VxWorks 默认使用基于优先级的抢占式调度,同优先级任务间不主动让出 CPU。启用时间片轮转后,系统为每个就绪的同优先级任务分配固定长度的时间片(tick 数),时间片耗尽后任务被移到就绪队列尾部,下一个同优先级任务获得 CPU。本案例通过两个任务各自打印执行序号来直观观察轮转效果。

完整实现代码

/* rr_demo.c - 时间片轮转调度演示 */
#include <vxWorks.h>
#include <taskLib.h>
#include <stdio.h>
#include <tickLib.h>

/* 任务函数:打印任务名与执行计数 */
static void rrTask(const char *name)
{
    int i;
    for (i = 0; i < 5; i++) {
        printf("%s: 第 %d 次执行\n", name, i + 1);
        taskDelay(1);   /* 延时1个tick,便于观察轮转 */
    }
}

/* 任务入口:创建两个同优先级任务并启动轮转调度 */
void rrDemo(void)
{
    int priority = 100;          /* 同优先级 */
    int options = VX_FP_TASK;    /* 浮点任务选项 */
    int stackSize = 20000;       /* 栈大小(字节) */

    /* 创建两个同优先级任务 */
    taskSpawn("tRR1", priority, options, stackSize,
              (FUNCPTR)rrTask, (int)"Task-1", 0,0,0,0,0,0,0,0,0);
    taskSpawn("tRR2", priority, options, stackSize,
              (FUNCPTR)rrTask, (int)"Task-2", 0,0,0,0,0,0,0,0,0);

    /* 启用时间片轮转:时间片为 3 个 tick */
    kernelTimeSlice(3);
}

编译与运行

  1. 将上述代码保存为 rr_demo.c,加入 VxWorks 工程编译链接。
  2. 在 VxWorks shell 中调用入口函数:rrDemo
  3. 观察串口终端输出。

验证方法与判定标准

预期输出特征:两个任务交替打印执行信息,且同一任务连续打印次数不超过约3次(对应3个tick时间片)。典型输出片段如下:

Task-1: 第 1 次执行
Task-1: 第 2 次执行
Task-2: 第 1 次执行
Task-2: 第 2 次执行
Task-1: 第 3 次执行
...

通过条件:

  • 两个任务均完成5次打印,无任务饿死;
  • 输出中 Task-1 与 Task-2 交替出现,而非一个任务连续执行完所有打印;
  • 若注释掉 kernelTimeSlice(3) 后重新运行,则第一个任务会连续打印5次后才轮到第二个任务——通过对比可确认时间片轮转已生效。

关键说明

  • kernelTimeSlice() 参数单位为系统 tick,需在工程中配置系统 tick 频率(通常为 60Hz 或 100Hz)。
  • 任务内 taskDelay(1) 用于降低打印速度,避免输出过快难以观察;实际轮转由内核时间片中断驱动,不依赖该延时。
  • 若需恢复默认的非轮转调度,调用 kernelTimeSlice(0) 即可。
t 0 3 6 9 12 15 Task-1 Task-1 Task-1 Task-2 Task-2 Task-2 时间片1 时间片3 时间片5 时间片2 时间片4 时间片6 → 轮转方向

上图展示了时间片轮转的执行序列:每个时间片为 3 个 tick,Task-1 与 Task-2 交替占用 CPU,形成公平调度。图中每个色块代表一个完整时间片,任务在时间片耗尽后让出处理器。