原创 十一、freeRTOS 优先级翻转与互斥信号量

2020-8-23 17:07 3073 22 3 分类: 汽车电子 文集: FreeRTOS

优先级翻转

优先级翻转简介:

就是高优先级的任务运行起来的效果好像成了低优先级,而低优先级比高优先级先运行。

优先级翻转如下所示:

优先级翻转过程:

为什么会发生优先级翻转?

因为两个任务(L和H)使用了同一个二值信号量,而在这两个任务之间,又有一个中等优先级的任务M,在这种情况下就容易发生优先级翻转。主要就是因为二值信号量产生的,低优先级任务L占用了信号量没有释放,导致高优先级任务请求信号量时无效,此时高优先级任务无法运行。

实验设计

总体思路是,任务L和任务H都请求信号量,当接收到信号量时,任务H立马释放信号量,而任务L做软件延时占用一段时间后再释放信号量,看程序的执行流程。测试代码如下所示:

  1. #include "main.h"
  2. #include "i2c.h"
  3. #include "usart.h"
  4. #include "gpio.h"
  5. #include "bsp_led.h"
  6. #include "bsp_key.h"
  7. #include "bsp_usart.h"
  8. #include "bsp_beep.h"
  9. #include "FreeRTOS.h"
  10. #include "task.h"
  11. #include "queue.h"
  12. #include "semphr.h"
  13. #include
  14. void start_task(void *pvParameters);
  15. void low_task(void *pvParameters);
  16. void middle_task(void *pvParameters);
  17. void high_task(void *pvParameters);
  18. /* 任务相关参数 */
  19. #define START_TASK_SIZE 256
  20. #define START_TASK_PRIO 1
  21. TaskHandle_t start_Task_Handle;
  22. #define LOW_TASK_SIZE 256
  23. #define LOW_TASK_PRIO 2
  24. TaskHandle_t low_task_Handle;
  25. #define MIDDLE_TASK_SIZE 256
  26. #define MIDDLE_TASK_PRIO 3
  27. TaskHandle_t middle_task_Handle;
  28. #define HIGH_TASK_SIZE 256
  29. #define HIGH_TASK_PRIO 4
  30. TaskHandle_t high_task_Handle;
  31. SemaphoreHandle_t binary_semphr = NULL; // 二值信号量句柄
  32. int main(void)
  33. {
  34. HAL_Init();
  35. SystemClock_Config();
  36. MX_GPIO_Init();
  37. MX_USART1_UART_Init();
  38. MX_I2C1_Init();
  39. MX_I2C2_Init();
  40. // 创建开始任务
  41. xTaskCreate((TaskFunction_t )start_task,
  42. (char * )"start_task",
  43. (uint16_t )START_TASK_SIZE,
  44. (void * )NULL,
  45. (UBaseType_t )START_TASK_PRIO,
  46. (TaskHandle_t * )&start_Task_Handle);
  47. vTaskStartScheduler(); // 开启调度器
  48. }
  49. void start_task(void *pvParameters)
  50. {
  51. taskENTER_CRITICAL();
  52. binary_semphr = xSemaphoreCreateBinary(); // 创建信号量
  53. if (binary_semphr != NULL)
  54. {
  55. printf("\n二值信号量创建成功");
  56. xSemaphoreGive(binary_semphr); // 释放信号量
  57. }
  58. else
  59. {
  60. printf("\n二值信号量创建失败");
  61. }
  62. // 创建低优先级任务
  63. xTaskCreate((TaskFunction_t )low_task,
  64. (char * )"low_task",
  65. (uint16_t )LOW_TASK_SIZE,
  66. (void * )NULL,
  67. (UBaseType_t )LOW_TASK_PRIO,
  68. (TaskHandle_t * )&low_task_Handle);
  69. // 创建中优先级任务
  70. xTaskCreate((TaskFunction_t )middle_task,
  71. (char * )"middle_task",
  72. (uint16_t )MIDDLE_TASK_SIZE,
  73. (void * )NULL,
  74. (UBaseType_t )MIDDLE_TASK_PRIO,
  75. (TaskHandle_t * )&middle_task_Handle);
  76. // 创建高优先级任务
  77. xTaskCreate((TaskFunction_t )high_task,
  78. (char * )"high_task",
  79. (uint16_t )HIGH_TASK_SIZE,
  80. (void * )NULL,
  81. (UBaseType_t )HIGH_TASK_PRIO,
  82. (TaskHandle_t * )&high_task_Handle);
  83. taskEXIT_CRITICAL();
  84. // 删除开始任务
  85. vTaskDelete(start_Task_Handle);
  86. }
  87. void low_task(void *pvParameters)
  88. {
  89. BaseType_t error_state;
  90. uint32_t limit;
  91. for (;;)
  92. {
  93. if (binary_semphr != NULL)
  94. {
  95. // 一直等待二值信号量
  96. error_state = xSemaphoreTake(binary_semphr, portMAX_DELAY);
  97. if (error_state == pdTRUE)
  98. {
  99. printf("\n低优先级任务获取到信号量,正在占用...");
  100. }
  101. else
  102. {
  103. printf("\n低优先级任务获取信号量失败");
  104. }
  105. #if 1
  106. // 模拟低优先级占用信号量
  107. for (limit = 0; limit < 5000000; limit++)
  108. {
  109. taskYIELD(); // 一直调用任务切换
  110. }
  111. #else
  112. HAL_Delay(8000);
  113. #endif
  114. // 释放二值信号量
  115. printf("\n低优先级任务占用信号量结束,即将释放");
  116. xSemaphoreGive(binary_semphr);
  117. }
  118. vTaskDelay(500);
  119. }
  120. }
  121. void middle_task(void *pvParameters)
  122. {
  123. for (;;)
  124. {
  125. printf("\n中优先级任务正在运行");
  126. vTaskDelay(1000);
  127. }
  128. }
  129. void high_task(void *pvParameters)
  130. {
  131. for (;;)
  132. {
  133. if (binary_semphr != NULL)
  134. {
  135. printf("\n高优先级任务正在等待信号量...");
  136. // 一直等待二值信号量
  137. xSemaphoreTake(binary_semphr, portMAX_DELAY);
  138. printf("\n高优先级任务获取到信号量,即将释放...");
  139. xSemaphoreGive(binary_semphr); // 释放信号量
  140. }
  141. vTaskDelay(1000);
  142. }
  143. }

程序运行结果如下所示:

 

互斥信号量

互斥信号量简介:

创建互斥信号量:

测试实验:修改上一个优先级翻转的实验,看测试结果。

修改过程:将使用二值信号量的地方修改成使用互斥信号量。

修改如下:

  1. void start_task(void *pvParameters)
  2. {
  3. taskENTER_CRITICAL();
  4. mutex_semphr = xSemaphoreCreateMutex(); // 创建互斥信号量
  5. if (mutex_semphr != NULL)
  6. {
  7. printf("\n互斥信号量创建成功");
  8. xSemaphoreGive(mutex_semphr); // 释放信号量
  9. }
  10. else
  11. {
  12. printf("\n互斥信号量创建失败");
  13. }
  14. // 创建低优先级任务
  15. xTaskCreate((TaskFunction_t )low_task,
  16. (char * )"low_task",
  17. (uint16_t )LOW_TASK_SIZE,
  18. (void * )NULL,
  19. (UBaseType_t )LOW_TASK_PRIO,
  20. (TaskHandle_t * )&low_task_Handle);
  21. // 创建中优先级任务
  22. xTaskCreate((TaskFunction_t )middle_task,
  23. (char * )"middle_task",
  24. (uint16_t )MIDDLE_TASK_SIZE,
  25. (void * )NULL,
  26. (UBaseType_t )MIDDLE_TASK_PRIO,
  27. (TaskHandle_t * )&middle_task_Handle);
  28. // 创建高优先级任务
  29. xTaskCreate((TaskFunction_t )high_task,
  30. (char * )"high_task",
  31. (uint16_t )HIGH_TASK_SIZE,
  32. (void * )NULL,
  33. (UBaseType_t )HIGH_TASK_PRIO,
  34. (TaskHandle_t * )&high_task_Handle);
  35. taskEXIT_CRITICAL();
  36. // 删除开始任务
  37. vTaskDelete(start_Task_Handle);
  38. }
  39. void low_task(void *pvParameters)
  40. {
  41. BaseType_t error_state;
  42. uint32_t limit;
  43. for (;;)
  44. {
  45. if (mutex_semphr != NULL)
  46. {
  47. // 一直等待互斥信号量
  48. error_state = xSemaphoreTake(mutex_semphr, portMAX_DELAY);
  49. if (error_state == pdTRUE)
  50. {
  51. printf("\n低优先级任务获取到信号量,正在占用...");
  52. }
  53. else
  54. {
  55. printf("\n低优先级任务获取信号量失败");
  56. }
  57. #if 0
  58. // 模拟低优先级占用信号量
  59. for (limit = 0; limit < 5000000; limit++)
  60. {
  61. taskYIELD(); // 一直调用任务切换
  62. }
  63. #else
  64. HAL_Delay(10000);
  65. #endif
  66. // 释放互斥信号量
  67. printf("\n低优先级任务占用信号量结束,即将释放");
  68. xSemaphoreGive(mutex_semphr);
  69. }
  70. vTaskDelay(500);
  71. }
  72. }
  73. void middle_task(void *pvParameters)
  74. {
  75. for (;;)
  76. {
  77. printf("\n中优先级任务正在运行");
  78. vTaskDelay(1000);
  79. }
  80. }
  81. void high_task(void *pvParameters)
  82. {
  83. for (;;)
  84. {
  85. if (mutex_semphr != NULL)
  86. {
  87. printf("\n高优先级任务正在等待信号量...");
  88. // 一直等待互斥信号量
  89. xSemaphoreTake(mutex_semphr, portMAX_DELAY);
  90. printf("\n高优先级任务获取到信号量,即将释放...");
  91. xSemaphoreGive(mutex_semphr); // 释放信号量
  92. }
  93. vTaskDelay(1000);
  94. }
  95. }

测试效果如下:

递归互斥信号量:

 转载于:https://blog.csdn.net/dingyc_ee/article/details/104115367

文章评论0条评论)

登录后参与讨论
我要评论
0
22
关闭 站长推荐上一条 /2 下一条