FreeRTOS 优先级翻转

1、优先级翻转的现象

在使用二值信号量的时候会遇到很常见的一个问题——优先级翻转,在实时系统中不允许出现这种现象,这样会破坏任务的预期顺序,可能会导致严重的后果。

如下图所示,任务 H 的优先级实际上降到了任务 L 的优先级水平。因为任务 H 要一直等待直到任务 L 释放其占用的那个共享资源。由于任务 M 剥夺了任务 L 的 CPU 使用权,使得任务 H 的情况更加恶化,这样就相当于任务 M 的优先级高于任务 H,导致优先级翻转。

序号

说明

(1)

任务H和任务M为阻塞状态,等待某一事件发生,此时任务L正在运行

(2)

此时任务L要访问共享资源,因此需要获取信号量

(3)

任务L成功获取信号量,此时信号量已无资源,任务L开始访问共享资源

(4)

此时任务H就绪,抢占任务L运行

(5)

任务H开始运行

(6)

此时任务H要访问共享资源,因此需要获取信号量,但信号量已无资源,因此任务H阻塞等待信号量资源

(7)

任务L继续运行

(8)

此时任务M就绪,抢占任务L运行

(9)

任务M正在运行

(10)

任务M运行完毕,继续阻塞

(11)

任务L继续运行

(12)

此时任务L对共享资源的访问操作完成,释放信号量,任务H因成功获取信号量,解除阻塞并抢占任务L运行

(13)

任务H得以运行

2、优先级翻转实验

2.1、实验设计

1、创建一个开始任务,在开始任务里面再新建一二值信号量,task 1(低), task 2(中), task3(高)三个任务后,删除开始任务;

2、task 1间隔 1000ms 获取一次二值信号量,并连续进行任务切换,模拟信号量被占用,随后释放信号量;

3、task 2间隔 1000ms 打印中间优先级的任务正在运行;

4、较task 1 延迟 500ms 获取信号量,此时信号量被task 1 占用,task 3 不能执行,而中优先级的 task 2 一直在执行

2.2、实验代码

//任务1
k_task_handle_t task1_handle;           //任务1 句柄
#define TSK1_PRIO            2         //任务1 优先级
#define TASK1_STK_SIZE       (1*512)   //任务1 分配的堆栈大小

//任务2
k_task_handle_t task2_handle;           //任务2 句柄
#define TSK2_PRIO            3         //任务2 优先级
#define TASK2_STK_SIZE       (1*512)   //任务2 分配的堆栈大小

//任务3
k_task_handle_t task3_handle;           //任务3 句柄
#define TSK3_PRIO            4         //任务3 优先级
#define TASK3_STK_SIZE       (1*512)   //任务3 分配的堆栈大小


//开始任务
k_task_handle_t start_task_handle;      //开始任务 句柄
#define START_TSK_PRIO       1          //开始任务 优先级
#define START_TSK_STK_SIZE   1024       //开始任务 分配的堆栈大小


#define TEST_TIME_QUANTA 100
k_sem_handle_t    g_usSem;  //信号量


void task1(void)
{
    uint32_t i = 0;
    while(1)
    {

            csi_kernel_sem_wait(g_usSem, portMAX_DELAY);
            my_printf("Low task running!\r\n");
            for(i=0;i<2000000;i++)
            {
              taskYIELD();                        
            }                
            csi_kernel_sem_post(g_usSem);
            csi_kernel_delay_ms(1000);
    }
}


void task2(void)
{
    while(1)
    {
            my_printf("Middle task running!\r\n");
            csi_kernel_delay_ms(1000);
    }
}

void task3(void)
{
    while(1)
    {
            csi_kernel_delay_ms(500);
            my_printf("High task Pend Semaphore\r\n");
            csi_kernel_sem_wait(g_usSem, portMAX_DELAY);
            my_printf("High task running!\r\n");
            csi_kernel_sem_post(g_usSem);
            csi_kernel_delay_ms(500);
    }
}



void start_task(void)
{
     //进入临界区
    taskENTER_CRITICAL(); 
    
    //创建二值信号量
    g_usSem = csi_kernel_sem_new(1, 1);
    if (g_usSem == NULL) 
    {
        printf("fail to create semaphore.\n");
    }

    //创建task 1
    csi_kernel_task_new((k_task_entry_t)task1, "task1", NULL, TSK1_PRIO, TEST_TIME_QUANTA, NULL, TASK1_STK_SIZE, &task1_handle);
    if (task1_handle == NULL) 
    {
        csi_kernel_sched_resume(0);
        my_printf("Fail to create task 1!\r\n");
    }

    //创建task 2
    csi_kernel_task_new((k_task_entry_t)task2, "task2", NULL, TSK2_PRIO, TEST_TIME_QUANTA, NULL, TASK2_STK_SIZE, &task2_handle);
    if (task2_handle == NULL) 
    {
        csi_kernel_sched_resume(0);
        my_printf("Fail to create task 2!\r\n");
    }
         
    //创建task 3
    csi_kernel_task_new((k_task_entry_t)task3, "task3", NULL, TSK3_PRIO, TEST_TIME_QUANTA, NULL, TASK3_STK_SIZE, &task3_handle);
    if (task3_handle == NULL) 
    {
        csi_kernel_sched_resume(0);
        my_printf("Fail to create task 3!\r\n");
    }
      

    //删除开始任务
    if(0 != csi_kernel_task_del(csi_kernel_task_get_cur()))
    {
            my_printf("Fail to delete start_task!\r\n");
    }
    else 
    {
            my_printf("start_task is deleted!\r\n");
    }

    
    //退出临界区
    taskEXIT_CRITICAL();            
}



void freertos_demo(void)
{

    my_printf("\r\n-->this is freertos task test demo!!!\r\n");                //print message
   
    //系统初始化
    csi_kernel_init();

        //创建开始任务
    csi_kernel_task_new((k_task_entry_t)start_task, "start_task", 0, START_TSK_PRIO, 0, 0, START_TSK_STK_SIZE, &start_task_handle);

        //任务调度开始
    csi_kernel_start();
        
}

2.3、实验现象

  • Task 3(High task)等待期间,Task 2(Middle task)已经运行了多次。

  • Task 2(Middle task)优先于Task 3(High task)运行,优先级翻转。

  • 在实际应用中,我们需要避免优先级翻转这种情况,因为其不符合抢占式内核的特点,所以就有了互斥信号量。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值