优先级翻转
高优先级的任务由于等待信号量而被挂起,导致不需要信号量的低优先级任务先运行。
实验目的
在使用二值信号量的时候会存在优先级翻转的问题,本实验通过模拟的方式实现优先级翻转,观察优先级翻转对抢占式内核的影响。
实验设计
设置了四个任务。
start_task:创建3个任务
high_task:高优先级任务,获取二值信号量触发
middle_task:中优先级任务,简单引用任务
low_task:低优先级任务,和高优先级任务一样需获取同一个二值信号量才能触发,占用信号量的时间比较长
实验代码:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "string.h"
#include "FreeRTOS.h"
#include "task.h"
#include "key.h"
#include "queue.h"
#include "timer.h"
#include "semphr.h"
/************************************************
************************************************/
//任务优先级
#define START_TASK_PRIO 1
//任务堆栈大小
#define START_STK_SIZE 128
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);
//任务优先级
#define LOW_TASK_PRIO 2
//任务堆栈大小
#define LOW_STK_SIZE 128
//任务句柄
TaskHandle_t Low_Handler;
//任务函数
void low_task(void *pvParameters);
//任务优先级
#define MIDDLE_TASK_PRIO 3
//任务堆栈大小
#define MIDDLE_STK_SIZE 128
//任务句柄
TaskHandle_t Middle_Handler;
//任务函数
void middle_task(void *pvParameters);
//任务优先级
#define HIGH_TASK_PRIO 4
//任务堆栈大小
#define HIGH_STK_SIZE 128
//任务句柄
TaskHandle_t High_Handler;
//任务函数
void high_task(void *pvParameters);
SemaphoreHandle_t SemphrHandle; // 二值信号量句柄
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
delay_init(); //延时函数初始化
uart_init(115200); //初始化串口
LED_Init(); //初始化LED
KEY_Init();
xTaskCreate((TaskFunction_t )start_task, //任务函数
(const char* )"start_task", //任务名称
(uint16_t )START_STK_SIZE, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )START_TASK_PRIO, //任务优先级
(TaskHandle_t* )&StartTask_Handler); //任务句柄
vTaskStartScheduler(); //开启任务调度
}
//开始任务任务函数
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //进入临界区
SemphrHandle = xSemaphoreCreateBinary();
if(SemphrHandle != NULL)
{
xSemaphoreGive(SemphrHandle);// 创建成功,释放信号量
}
else
{
printf("xSemaphoreCreateCounting Failed!\r\n");
}
xTaskCreate((TaskFunction_t) low_task,
(const char * ) "low_task",
(uint16_t ) LOW_STK_SIZE,
(void * ) NULL,
(UBaseType_t ) LOW_TASK_PRIO,
(TaskHandle_t* ) &Low_Handler);
xTaskCreate((TaskFunction_t) middle_task,
(const char * ) "middle_task",
(uint16_t ) MIDDLE_STK_SIZE,
(void * ) NULL,
(UBaseType_t ) MIDDLE_TASK_PRIO,
(TaskHandle_t* ) &Middle_Handler);
xTaskCreate((TaskFunction_t) high_task,
(const char * ) "high_task",
(uint16_t ) HIGH_STK_SIZE,
(void * ) NULL,
(UBaseType_t ) HIGH_TASK_PRIO,
(TaskHandle_t* ) &High_Handler);
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
//任务函数
void low_task(void *pvParameters)
{
int i = 0;
while(1)
{
xSemaphoreTake(SemphrHandle,portMAX_DELAY); // 请求信号量
printf("1_low task is running!\r\n");
for(;i<2000000;i++) // 延时占用
{
//delay_us(1000);
taskYIELD();// 任务切换
}
xSemaphoreGive(SemphrHandle);// 释放信号量
vTaskDelay(1000); //延时1s,也就是1000个时钟节拍
}
}
//任务函数
void middle_task(void *pvParameters)
{
while(1)
{
printf("2_middle task is running!\r\n");
vTaskDelay(1000); //延时1s,也就是1000个时钟节拍
}
}
//任务函数
void high_task(void *pvParameters)
{
while(1)
{
printf("high task pend!!!\r\n");
xSemaphoreTake(SemphrHandle,portMAX_DELAY); // 请求信号量
printf("3_high task is running!\r\n");
xSemaphoreGive(SemphrHandle);// 释放信号量
vTaskDelay(1000); //延时1s,也就是1000个时钟节拍
}
}
实验现象:
high task pend!!!
3_high task is running!
2_middle task is running!
1_low task is running!
high task pend!!!
2_middle task is running!
2_middle task is running!
2_middle task is running!
2_middle task is running!
3_high task is running!
2_middle task is running!
high task pend!!!
3_high task is running!
1_low task is running!
2_middle task is running!
high task pend!!!
3_high task is running!
1_low task is running!
high task pend!!!高任务在申请请求时,由于被低任务占用信号量,导致2_middle task is running!多次执行