rtos07:任务调度实质

1.预备知识:

1.1空闲任务:
1.1.1空闲任务的创建:

空闲任务在开启调度器函数vTaskStartScheduler()中创建,空闲任务的函数将会做:

  • 检查自杀的任务,做清理工作
  • 如果user配置了开启hook函数,将会调用hook函数,用户可以在hook函数里面添加相应功能

1.2两个Delay:

  • vTaskDelay:指定的是阻塞的时间
  • vTaskDelayUntil:指定的是任务执行的间隔、周期

freertos有一个使用定时器每隔若干时间会产生一次中断(cubemx里的宏TICK_RATE_Hz=中断频率,1ms),类似于人的心跳,每一次中断之间的时间间隔被称为Tick,vTaskDelay(n)的n指的就是delay n个Tick。

2.任务的管理与调度 

2.1任务调度特性:

a. 高优先级的任务未执行完,低优先级的任务无法运行

b. 一旦高优先级任务就绪,马上运行

c. 最高优先级的任务有多个,它们轮流运行

2.2任务调度本质:
使用链表来管理:

理论

任务的最高优先级=56:

跳转到定义,宏=数组成员是链表的数组,共56个:

PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ] = {0};
PRIVILEGED_DATA static List_t xDelayedTaskList1 = {0};
PRIVILEGED_DATA static List_t xDelayedTaskList2 = {0};

每个链表存放一个优先级的任务:(以3个任务优先级均=24为例) 


在代码中体现为: 

BaseType_t xTaskCreate():

  • 当创建任务的时候,任务将被添加到就绪中:
  • 判断添加进哪个就绪列表以及当前任务优先级是否更高,pxCurrentTCB指向优先级最高的列表:
BaseType_t xTaskCreate()
{
      /*...*/
        #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 Macro has been     consolidated. */
        {
            pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB;
        }
        #endif 
        prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxNewTCB );
        /*将新任务添加进ReadyList*/
        vAddTaskToReadyList( pxNewTCB ); 
        xReturn = pdPASS;
    
     /*...*/
        if( xSchedulerRunning == pdFALSE )
    {
        if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority )
        {
            pxCurrentTCB = pxNewTCB;
        }
        else
        {
               mtCOVERAGE_TEST_MARKER();
        }
    }
    else
    {
        // 其他代码
    }
}

void vTaskStartScheduler( void ):

在启动任务调度器函数里面会创建空闲任务,优先级=0,最低,此时pxCurrentTCB指向当前创建完毕的最高优先级任务(task3)。

此为优先级最高的任务执行。 

int main( void )
{
	prvSetupHardware();
	
      /* 初始化rtos任务*/
    MX_Freertos_Init();

	xTaskCreate(vTask1, "Task 1", 1000, NULL, 1, NULL);
	xTaskCreate(vTask2, "Task 2", 1000, NULL, 1, NULL);

	/* 启动调度器 */
	vTaskStartScheduler();

	/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
	return 0;
}
        /*启动任务调度器*/
void vTaskStartScheduler( void )
{
    BaseType_t xReturn;

    /* Add the idle task at the lowest priority. */
    #if( configSUPPORT_STATIC_ALLOCATION == 1 )
    {
        staticTask_t *pxIdleTaskTCBBuffer = NULL;
        StackType_t *pxIdleTaskStackBuffer = NULL;
        uint32_t ulIdleTaskStackSize;

        vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );

        /* 创建空闲任务*/
        xIdleTaskHandle = xTaskCreateStatic(
            prvIdleTask,
            configIDLE_TASK_NAME,
            ulIdleTaskStackSize,
            ( void * ) NULL, /*lint !e961. The cast is not redundant as per the MISRA exception. */
            ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
            pxIdleTaskStackBuffer,
            pxIdleTaskTCBBuffer ); parameter is not used. */
    }
    #endif

    if( xIdleTaskHandle != NULL )
    {
        /* ... */
    }
}

task3释放任务调度权后,执行同优先级的任务,时间片轮转:

每一次Tick中断进行一次任务调度,从上往下遍历ReadyList,找到第一个非空的链表,然后依次取出其中任务来运行(pxCurrentTCB指向下一个任务)。

 

此时若创建一个新任务task5,且优先级=25,由 一旦高优先级任务就绪,马上运行的原则和任务创建完即为就绪态,pcCurrentTCB立刻指向task5,开始运行。

 在task5内部若存在延时,则运行到延时时,task5进入blocked状态,此时task5被从ReadyList中删除,移到其他链表里(某一个DelayTaskList):

 Delay过程中,将触发Tick调度:

  • cnt++         累加计数
  • 判断DelayTaskList里的任务是否可恢复回ReadyTask。(比一般Tick多做的)
  • 检查是否有新的任务需要运行,触发PendSV,并执行上下文切换。

PendSV:

  • 保存当前任务寄存器、堆栈指针等
  • 寄存器PC值会被恢复为即将运行的任务的任务函数,B开始运行

由于刚才Task5已经从就绪列表里面删除,此时将从就序列表(优先级=24)的进行,又由于刚刚Task1,3均已经运行过,此时从Task2运行。(每个就绪列表里有一个index记录谁运行过了)。

Delay结束后,恢复task5进入就绪列表。一样发起Tick调度:

  • 从上往下遍历ReadyList,找到第一个非空的链表,然后依次取出其中任务来运行(pxCurrentTCB指向下一个任务)

若在下次运行1时暂停task5: 

则task5将被从就绪列表中移除,放入挂起链表中:

PRIVILEGED_DATA static List_t xSuspendedTaskList = {0};

只有再次调用:task5才会被恢复回就绪列表。

vTaskResume(xSoundTaskHandle);

 

3.总结:

调度的触发情况:

时间片轮转中:Tick中断触发一次

任务运行:任务运行完毕,释放任务调度权/被高优先级任务打断。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值