当前位置: 首页 > article >正文

400行程序写一个实时操作系统(十七):调度算法的实现

前言

在上一篇博客笔者介绍了操作系统中的调度算法,调度算法的本质就是选择下一个任务。

如果读者认真看了上一篇文章的内容,那么接下来讲解的Sparrow的算法应该是非常清晰易懂的。

在实时操作系统Sparrow RTOS中,我们引入了优先级的概念,就是为了使任务的运行更加具有实时性,优先级由我们手动进行调整,往往我们希望优先级高的任务优先执行,那么,该怎么做呢?

调度算法的设计

我们使用ReadyBitTable这个uint32_T类型的变量来标识就绪的任务,只要任务是就绪态的,我们就执行 ReadyBitTable |= (1 << uxPriority)操作,这样ReadyBitTable 中为1的位就表示有就绪的任务。

那么如何得到对应的优先级数字呢?这里我们可以计算从高位到低位,离最近的1有多少个0,然后用31减去这个数目,就可以得到优先级的数字了。

在arm架构中,恰好有这么一条汇编指令clz,它可以计算从高位到低位,离最近的1之间的0的数目,正好符合我们的需求。

举例如下:

就绪表clz的结果最大优先级
ReadyBitTable00000000000000000000000000000100292
ReadyBitTable00000000000000000000000100000011238

不知道读者发现没有,其实这种方法跟上一节中所讲的RTThread的算法思想是一样的,只是我们使用clz指令代替了查表法。在FreeRTOS和RT-Thread等RTOS中,其实都有使用clz指令的方法,它们跟Sparrow的算法都大差不差。

修改程序

既然我们已经知道了思路,那么让我们开始写代码:

uint32_t ReadyBitTable = 0;//添加到合适的地方即可



__attribute__( ( always_inline ) ) static inline uint8_t FindHighestPriority( void )
{
    uint8_t TopZeroNumber;
    uint8_t temp;
    __asm volatile
            (
            "clz %0, %2\n"
            "mov %1, #31\n"
            "sub %0, %1, %0\n"
            :"=r" (TopZeroNumber),"=r"(temp)
            :"r" (ReadyBitTable)
            );
    return TopZeroNumber;
}

void vTaskSwitchContext( void )
{
    pxCurrentTCB = TcbTaskTable[ FindHighestPriority()];
}

修改xTaskCreat函数,添加一行代码:

void xTaskCreate( TaskFunction_t pxTaskCode,
                  const uint16_t usStackDepth,
                  void * const pvParameters,//You can use it for debugging
                  uint32_t uxPriority,
                  TaskHandle_t * const self )
{
    uint32_t *topStack =NULL;
    TCB_t *NewTcb = (TCB_t *)heap_malloc(sizeof(TCB_t *));
    *self = ( TCB_t *) NewTcb;

    TcbTaskTable[uxPriority] = NewTcb;//

    NewTcb->uxPriority = uxPriority;
    NewTcb->pxStack = ( uint32_t *) heap_malloc( ( ( ( size_t ) usStackDepth ) * sizeof( uint32_t * ) ) );
    topStack =  NewTcb->pxStack + (usStackDepth - (uint32_t)1) ;
    topStack = ( uint32_t *) (((uint32_t)topStack) & (~((uint32_t) aligment_byte)));
    NewTcb->pxTopOfStack = pxPortInitialiseStack(topStack,pxTaskCode,pvParameters,self);
    pxCurrentTCB = NewTcb;

    ReadyBitTable |= (1 << uxPriority); //添加这一行
}

修改空闲任务,任务内容为进入低功耗模式:

void EnterSleepMode(void)
{
    SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
    __WFI();
}


//Task handle can be hide, but in order to debug, it must be created manually by the user
TaskHandle_t leisureTcb = NULL;

void leisureTask( )
{//leisureTask content can be manually modified as needed
    while (1) {
        EnterSleepMode();
    }
}

实验

验证思路

设置一个任务的优先级为最大,观察这个任务是不是一直在执行。

程序

修改任务:

//Task Area!The user must create task handle manually because of debugging and specification
TaskHandle_t tcbTask1 = NULL;
TaskHandle_t tcbTask2 = NULL;


void led_bright( )
{
    while (1) {

    }
}

void led_extinguish( )
{
    while (1) {
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
        HAL_Delay(500);
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
        HAL_Delay(500);
        switchTask();
    }
}

当然,请确保led_extinguish优先级足够大:

void APP( )
{

    xTaskCreate(    led_bright,
                    128,
                    NULL,
                    1,
                    &tcbTask1
    );

    xTaskCreate(    led_extinguish,
                    128,
                    NULL,
                    8,
                    &tcbTask2
    );
}

实验现象:

stm32f103c8t6上的led灯一直在闪烁,说明任务led_extinguish一直在执行。

总结

介绍了Sparrow的调度算法,然后编写程序实现了优先级抢占算法的设计,最后修改原先的工程对调度算法进行验证。

本次实验的文件夹的地址:skaiui2/SKRTOS_sparrow at experiment

有需要的读者可以自取。


http://www.kler.cn/a/369610.html

相关文章:

  • Tangible Software Solutions 出品最准确可靠的源代码转换器
  • Python日志系统详解:Logging模块最佳实践
  • QT建立工程时出现了:Reading Project
  • Spring boot 配置文件的加载顺序
  • 【设计模式系列】代理模式(八)
  • Nodejs安装配置及创建vue项目
  • Sqoop的安装配置及使用
  • 梧桐数据库锁处理过程
  • Cesium基础-(Entity)-(point)
  • (STM32笔记)十二、DMA的基础知识与用法
  • OBOO鸥柏丨液晶拼接大屏KVM分布式输入输出节点控制系统技术
  • C/C++每日一练:实现冒泡排序
  • Spring Boot 3项目创建与示例(Web+JPA)
  • 厨艺爱好者的在线聚集地:Spring Boot实现
  • 2022 icpc南京(I,G,A,D,M,B)
  • GATK Funcotator 详解
  • [论文阅读]Large Language Model guided Protocol Fuzzing
  • MinIO服务部署指南
  • 线程的理解及基本操作
  • 如何使用 Vite 创建一个项目(Vue 或者 React)
  • Linux常用命令 yum 命令介绍
  • Eslint检查报错-关闭vue项目中的eslint
  • 代码工艺:SQL 优化的细节
  • C++初阶教程——C++入门
  • Go第三方框架--gorm框架(二)
  • 优选算法专题一 ——双指针算法