袁曼妮 发表于 2025-6-8 13:21:49

FreeRTOS 简单内核实现8 时间片轮询

0、思考与回答

0.1、思考一

为什么要增加时间片轮询?
目前的 RTOS 内核已经支持抢占优先级,即高优先级的任务会抢占低优先级的任务得到执行,但是对于同等优先级的任务,如果不支持时间片轮询,则只能有一个任务运行,并且由于优先级相同所以除延时阻塞到期外也不会发生任务调度,因此需要增加时间片轮询保证同等优先级的任务能得到轮流执行
1、内核程序修改

1.1、xTaskIncrementTick( )

在该函数中除了任务延时阻塞时间到期产生任务调度外,增加支持时间片轮询的任务切换,具体如下所示
/*task.c*/
BaseType_t xTaskIncrementTick(void)
{
        // 省略未修改的程序
        ......
#if((configUSE_PREEMPTION == 1) && (configUSE_TIME_SLICING == 1))
        // 支持时间片轮询
        if(listCURRENT_LIST_LENGTH(&(pxReadyTasksLists)) > 1)
        {
                xSwitchRequired = pdTRUE;
        }
#endif
        return xSwitchRequired;
}/* FreeRTOSConfig.h */
// 支持时间片轮询
#define configUSE_TIME_SLICING                  11.2、原理

假设当前系统中只存在两个优先级相同的任务,时间片轮询任务切换流程如下
xTaskIncrementTick()
-> vTaskSwitchContext()
-> taskSELECT_HIGHEST_PRIORITY_TASK()
-> listGET_OWNER_OF_NEXT_ENTRY()
当进入滴答定时器中断服务函数时,如果发现就绪链表数组中的某个链表中链表项的数量大于 1 ,则表示该优先级下有不止一个任务,此时就可以产生任务调度
当有任务调度产生的时候,会调用 vTaskSwitchContext() 和 taskSELECT_HIGHEST_PRIORITY_TASK() 两个函数寻找当前的最高优先级任务,但是系统中只有两个优先级相同的任务,因此最高优先级仍然没变,但是在这个优先级下返回的任务却变成了下一个
为什么呢?
关键在于 listGET_OWNER_OF_NEXT_ENTRY() 函数,这个宏函数每次调用会获取链表中下一个链表项的 pvOwner 参数,由于是双向链表,因此会不断的循环链表中的链表项(两个同等优先级的任务),每次发生任务调度就会切换一次任务,所以就实现了时间片轮询
3、实验

3.1、测试

参考 FreeRTOS 简单内核实现6 优先级 "3.1、测试" 小节内容,将两个任务的优先级修改为一样,然后在两个任务中均使用软件延时模拟任务连续运行,具体程序如下所示
/* main.c */
/* USER CODE BEGIN Includes */
#include "FreeRTOS.h"
/* USER CODE END Includes */

/* USER CODE BEGIN PV */
// 软件延时
void delay(uint32_t count)
{
        for(;count!=0;count--);
}

TaskHandle_t Task1_Handle;
#define TASK1_STACK_SIZE                  128
StackType_t Task1Stack;
TCB_t Task1TCB;
UBaseType_t Task1Priority = 2;

TaskHandle_t Task2_Handle;
#define TASK2_STACK_SIZE                  128
StackType_t Task2Stack;
TCB_t Task2TCB;
UBaseType_t Task2Priority = 2;

// 任务 1 入口函数
void Task1_Entry(void *parg)
{
        for(;;)
        {
                HAL_GPIO_TogglePin(GREEN_LED_GPIO_Port, GREEN_LED_Pin);
                delay(10000000);
        }
}
// 任务 2 入口函数
void Task2_Entry(void *parg)
{
        for(;;)
        {
                HAL_GPIO_TogglePin(ORANGE_LED_GPIO_Port, ORANGE_LED_Pin);
                delay(10000000);
        }
}
/* USER CODE END PV */

/* USER CODE BEGIN 2 */
// 创建任务 1 和 2
Task1_Handle = xTaskCreateStatic((TaskFunction_t)Task1_Entry,
                                                               (char *)"Task1",
                                                               (uint32_t)TASK1_STACK_SIZE,
                                                               (void *)NULL,
                                                               (UBaseType_t)Task1Priority,
                                                               (StackType_t *)Task1Stack,
                                                               (TCB_t *)&Task1TCB);
                                                                                                               
Task2_Handle = xTaskCreateStatic((TaskFunction_t)Task2_Entry,
                                                               (char *)"Task2",
                                                               (uint32_t)TASK2_STACK_SIZE,
                                                               (void *) NULL,
                                                               (UBaseType_t)Task2Priority,
                                                               (StackType_t *)Task2Stack,
                                                               (TCB_t *)&Task2TCB );
// 启动任务调度器,永不返回
vTaskStartScheduler();
/* USER CODE END 2 */将 configUSE_TIME_SLICING 调整为 0 ,然后烧录程序,仍然使用逻辑分析仪捕获两个 LED 的引脚电平,结果如下图所示

可以发现在不启用时间片轮询时,由于两个任务优先级一致,并且两个任务模拟连续运行,因此只有任务 Task2 被运行 (为什么是 Task2 ?)
将 configUSE_TIME_SLICING 调整为 1,然后烧录程序,仍然使用逻辑分析仪捕获两个 LED 的引脚电平,结果如下图所示

可以发现,对于优先级相同且连续运行的任务几乎是在同时运行,其实是因为每个时间片(滴答定时器间隔)都发生了一次任务调度
3.2、待改进

当前 RTOS 简单内核已实现的功能有

[*]静态方式创建任务
[*]手动切换任务
[*]临界段保护
[*]任务阻塞延时
[*]支持任务优先级
[*]阻塞链表
[*]时间片轮询
后续 RTOS 简单内核可以增加

[*]任务间通信机制
[*]信号量
[*]互斥锁
[*]消息队列
[*]......

[*]其他功能
[*]软件定时器
[*]......


来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: FreeRTOS 简单内核实现8 时间片轮询