B站Michale_ee——ESP32_IDF SDK——FreeRTOS_4信号量、互斥量
- 信号量可以控制任务同步,即任务之间的执行按照一定顺序执行;
- RTOS中的任务间通信、任务同步、任务互斥;
- 任务间通信:不同任务间进行数据的交换和信息的传递,可以通过消息队列等方式;
- 任务同步:确保任务按照特定顺序执行,可以通过信号量、事件标志组等方式;
- 任务互斥:保证同一时刻只能有一个任务访问临界资源,防止资源同时方式访问或造成资源数据不一致;
一、二进制信号量
1.二进制信号量简介
- 二进制信号只有0和1两个值。
- 信号量为1时,任务可以获取信号量并执行该任务;
- 信号量为0时,任务获取不到信号量,进入阻塞状态,暂停执行;
2.二进制信号量API简介
(1)创建二进制信号量
(2)释放信号量
(3)获取信号量
3.示例代码及运行结果
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_system.h"
#include "freertos/semphr.h" // add by lxlint iCount = 0;
SemaphoreHandle_t Semphr_Handle;void Task1(void *pvparam)
{while(1){xSemaphoreTake(Semphr_Handle, portMAX_DELAY);for(int i=0; i<10; i++){iCount++;printf("Task1 iCount:%d\n", iCount);vTaskDelay(pdMS_TO_TICKS(1000));}xSemaphoreGive(Semphr_Handle);vTaskDelay(pdMS_TO_TICKS(1000));}
}void Task2(void *pvparam)
{while(1){xSemaphoreTake(Semphr_Handle, portMAX_DELAY);for(int i=0; i<10; i++){iCount++;printf("Task2 iCount:%d\n", iCount);vTaskDelay(pdMS_TO_TICKS(1000));}xSemaphoreGive(Semphr_Handle);vTaskDelay(pdMS_TO_TICKS(1000));}
}void app_main(void)
{Semphr_Handle = xSemaphoreCreateBinary();xSemaphoreGive(Semphr_Handle);xTaskCreate(Task1, "Task1", 1024*5, NULL, 1, NULL);xTaskCreate(Task2, "Task2", 1024*5, NULL, 1, NULL);
}
二、计数型信号量
1.计数型信号量简介
- 计数型信号量的值可大于1;
- 计数型信号量用于对多个资源进行管理;例如:停车场中有多个停车位,用计数型信号量表示停车位的个数:有车进入,计数型信号量减1;有车开出,计数型信号量加1;
2.计数型信号量API简介
(1)获取可用信号量的个数
(2)释放信号量、获取信号量API 同 二进制信号量
(3)创建计数型信号量
3.示例代码及运行结果
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_system.h"
#include "freertos/semphr.h" // add by lxlSemaphoreHandle_t Semphr_Handle;void CarInTask(void *pvparam)
{UBaseType_t EmptySpaceCount = 0;BaseType_t iResult;while(1){EmptySpaceCount = uxSemaphoreGetCount(Semphr_Handle);printf("EmptySpaceCount:%d\n", EmptySpaceCount);iResult = xSemaphoreTake(Semphr_Handle, 0);if(iResult == pdPASS)printf("One Car in!\n");elseprintf("No Space!\n");vTaskDelay(pdMS_TO_TICKS(1000));}
}void CarOutTask(void *pvparam)
{while(1){vTaskDelay(pdMS_TO_TICKS(6000));xSemaphoreGive(Semphr_Handle);}
}void app_main(void)
{Semphr_Handle = xSemaphoreCreateCounting(5, 5);// xSemaphoreGive(Semphr_Handle);xTaskCreate(CarInTask, "CarInTask", 1024*5, NULL, 1, NULL);xTaskCreate(CarOutTask, "CarOutTask", 1024*5, NULL, 1, NULL);
}
三、互斥量
1.互斥量简介
- 互斥量用于控制任务对临界资源的访问,确保一段时间内只有一个任务访问临界资源;
- 互斥量和二值信号量十分相似,但互斥量有优先级继承机制,能避免出现优先级反转的情况;
-
优先级继承机制:持有互斥锁的任务的优先级会在另一个更高优先级的任务尝试获取同一互斥锁时被提升。已经持有互斥锁的任务被称为“继承”了试图“夺取”同一互斥锁的任务的优先级。当互斥锁被释放时,继承的优先级将被“取消继承”(即,在持有互斥锁期间继承了更高优先级的任务将在互斥锁被释放后恢复到其原始优先级)。
-
优先级反转:
-
2.互斥量API简介
(1)创建互斥量
(2)释放信号量、获取信号量API 同 二进制信号量
3.示例代码及运行结果
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_system.h"
#include "freertos/semphr.h" // add by lxlSemaphoreHandle_t MutexHandle = NULL;
TaskHandle_t Task1Handle = NULL;void Task1(void *pvparam)
{BaseType_t iRet;UBaseType_t Task1Priority;while(1){printf("Task1 begin\n");iRet = xSemaphoreTake(MutexHandle, 1000);if(iRet == pdPASS){printf("Task1 Take Mutex Successfully\n");for(int i=0; i<5; i++){printf("Task1 i=%d\n", i);Task1Priority = uxTaskPriorityGet(NULL);printf("Task1 Priority:%d\n", Task1Priority);vTaskDelay(pdMS_TO_TICKS(1000));}xSemaphoreGive(MutexHandle);printf("Task1 Give Mutex!\n");vTaskDelay(pdMS_TO_TICKS(5000));}else{printf("Task1 Take Mutex Fail\n");vTaskDelay(pdMS_TO_TICKS(1000));}}}void Task2(void *pvparam)
{printf("Task2 begin\n");vTaskDelay(pdMS_TO_TICKS(1000));while(1){;}
}void Task3(void *pvparam)
{BaseType_t iRet;UBaseType_t Task1Priority;printf("Task3 begin\n");vTaskDelay(pdMS_TO_TICKS(1000));while(1){iRet = xSemaphoreTake(MutexHandle, 1000);if(iRet == pdPASS){printf("Task3 Take Mutex Successfully\n");Task1Priority = uxTaskPriorityGet(Task1Handle);printf("Task1 Priority :%d\n", Task1Priority);for(int i=0; i<5; i++){printf("Task3 i=%d\n", i);vTaskDelay(pdMS_TO_TICKS(1000));}xSemaphoreGive(MutexHandle);printf("Task3 Give Mutex!\n");vTaskDelay(pdMS_TO_TICKS(5000));}else{printf("Task3 Take Mutex Fail\n");vTaskDelay(pdMS_TO_TICKS(1000));}}
}void app_main(void)
{MutexHandle = xSemaphoreCreateMutex();vTaskSuspendAll();xTaskCreatePinnedToCore(Task1, "Task1", 1024*5, NULL, 1, &Task1Handle, 1); //! ESP32-S3为双核,CPU0主要运行WiFi和蓝牙;CPU1用于运行应用程序;xTaskCreatePinnedToCore(Task2, "Task2", 1024*5, NULL, 2, NULL, 1);xTaskCreatePinnedToCore(Task3, "Task3", 1024*5, NULL, 3, NULL, 1);xTaskResumeAll();
}
四、递归互斥量
1.递归互斥锁的使用场景
- 任务1在使用资源A的同时,之后又需要使用资源B
- 如果用互斥量,需要创建2个互斥量,在使用资源时上锁,不需要使用资源时,解锁
- 用递归互斥量只需要创建1个,在使用1次资源时,上1次锁,不需要使用资源时,解1次锁;
2.递归互斥量的API简介
(1)创建递归互斥量
(2)获取递归互斥量
(3)释放递归互斥量
3.示例代码及运行结果
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_system.h"
#include "freertos/semphr.h" // add by lxlSemaphoreHandle_t RecursiveMutexHandle = NULL;
TaskHandle_t Task1Handle = NULL;void Task1(void *pvparam)
{while(1){// printf("--------------------------\n");printf("Task1 begin\n");xSemaphoreTakeRecursive(RecursiveMutexHandle, portMAX_DELAY);printf("Task1 Take A!\n");for(int i=0; i<5; i++){printf("Task1 i:%d for A\n", i);vTaskDelay(pdMS_TO_TICKS(1000));}xSemaphoreTakeRecursive(RecursiveMutexHandle, portMAX_DELAY);printf("Task1 Take B!\n");for(int i=0; i<5; i++){printf("Task1 i:%d for B\n", i);vTaskDelay(pdMS_TO_TICKS(1000));}printf("Task1 Give B!\n");xSemaphoreGiveRecursive(RecursiveMutexHandle);vTaskDelay(pdMS_TO_TICKS(3000));printf("Task1 Give A!\n");xSemaphoreGiveRecursive(RecursiveMutexHandle);vTaskDelay(pdMS_TO_TICKS(3000));}
}void Task2(void *pvparam)
{vTaskDelay(pdMS_TO_TICKS(1000));while(1){// printf("--------------------------\n");printf("Task2 begin\n");xSemaphoreTakeRecursive(RecursiveMutexHandle, portMAX_DELAY);printf("Task2 Take A!\n");for(int i=0; i<5; i++){printf("Task2 i:%d for A\n", i);vTaskDelay(pdMS_TO_TICKS(1000));}printf("Task2 Give A!\n");xSemaphoreGiveRecursive(RecursiveMutexHandle);vTaskDelay(pdMS_TO_TICKS(3000));}
}void app_main(void)
{RecursiveMutexHandle = xSemaphoreCreateRecursiveMutex();vTaskSuspendAll();xTaskCreatePinnedToCore(Task1, "Task1", 1024*5, NULL, 1, &Task1Handle, 1); //! ESP32-S3为双核,CPU0主要运行WiFi和蓝牙;CPU1用于运行应用程序;xTaskCreatePinnedToCore(Task2, "Task2", 1024*5, NULL, 1, NULL, 1);xTaskResumeAll();
}