FreeRTOS中,信号量(Semaphore)是一种用于任务间同步和互斥的机制。信号量可以分为二进制信号量(Binary Semaphore)、计数信号量(Counting Semaphore)和互斥信号量(Mutex)。下面详细介绍信号量的创建、使用和释放。
1. 创建信号量
二进制信号量:
SemaphoreHandle_t xBinarySemaphore;
void createBinarySemaphore() {
xBinarySemaphore = xSemaphoreCreateBinary();
if (xBinarySemaphore == NULL) {
// 信号量创建失败
} else {
// 信号量创建成功
}
}
计数信号量:
SemaphoreHandle_t xCountingSemaphore;
void createCountingSemaphore() {
xCountingSemaphore = xSemaphoreCreateCounting(maxCount, initialCount);
if (xCountingSemaphore == NULL) {
// 信号量创建失败
} else {
// 信号量创建成功
}
}
互斥信号量:
SemaphoreHandle_t xMutex;
void createMutex() {
xMutex = xSemaphoreCreateMutex();
if (xMutex == NULL) {
// 互斥信号量创建失败
} else {
// 互斥信号量创建成功
}
}
2. 使用信号量:
获取信号量:
if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
// 成功获取信号量
} else {
// 获取信号量失败
}
xSemaphore
:要获取的信号量句柄。portMAX_DELAY
:等待时间,portMAX_DELAY
表示一直等待。
释放信号量:
if (xSemaphoreGive(xSemaphore) == pdTRUE) {
// 成功释放信号量
} else {
// 释放信号量失败
}
xSemaphore
:要释放的信号量句柄。
三种信号量的区别:
1. 二进制信号量(Binary Semaphore)
特点:
- 只有两个状态:0(不可用)和1(可用)。
- 主要用于任务之间的同步。
应用场景:
- 任务同步:一个任务等待另一个任务或中断完成某个事件。
- 事件标志:用来表示某个事件是否发生。
SemaphoreHandle_t xBinarySemaphore = xSemaphoreCreateBinary();
// 在一个任务或中断中释放信号量
xSemaphoreGive(xBinarySemaphore);
// 在另一个任务中获取信号量
if (xSemaphoreTake(xBinarySemaphore, portMAX_DELAY) == pdTRUE) {
// 处理事件
}
2. 计数信号量(Counting Semaphore)
特点:
- 有一个计数值,可以递增和递减。
- 初始值和最大值在创建时指定。
- 主要用于管理资源访问。
应用场景:
- 资源管理:比如管理多个相同类型的资源(如多个相同的外设或缓冲区)。
- 事件计数:记录多个事件的发生次数。
示例:
SemaphoreHandle_t xCountingSemaphore = xSemaphoreCreateCounting(maxCount, initialCount);
// 在一个任务或中断中释放信号量(增加计数)
xSemaphoreGive(xCountingSemaphore);
// 在另一个任务中获取信号量(减少计数)
if (xSemaphoreTake(xCountingSemaphore, portMAX_DELAY) == pdTRUE) {
// 使用一个资源
}
3. 互斥信号量(Mutex)
特点:
- 主要用于实现互斥访问,防止多个任务同时访问共享资源。
- 优先级继承机制:如果一个高优先级任务等待一个被低优先级任务持有的互斥信号量,低优先级任务会临时提升其优先级,防止优先级反转。
应用场景:
- 互斥访问:保护临界区,防止并发访问造成数据不一致。
在FreeRTOS中,当一个互斥信号量(Mutex)被释放,并且有多个优先级相同的任务正在等待该信号量时,哪个任务会首先获得信号量取决于调度器的策略。FreeRTOS使用基于优先级的抢占式调度,并且在同优先级任务之间,调度器采用轮询调度(Round Robin Scheduling)。
示例:
SemaphoreHandle_t xMutex = xSemaphoreCreateMutex();
// 在一个任务中获取互斥信号量
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
// 访问共享资源
// 释放互斥信号量
xSemaphoreGive(xMutex);
}
示例,展示如何创建、使用和释放二进制信号量:
#include "FreeRTOS.h"
#include "semphr.h"
SemaphoreHandle_t xBinarySemaphore;
void vTask1(void *pvParameters) {
for (;;) {
// 尝试获取信号量
if (xSemaphoreTake(xBinarySemaphore, portMAX_DELAY) == pdTRUE) {
// 成功获取信号量
// 执行任务
// 释放信号量
xSemaphoreGive(xBinarySemaphore);
}
}
}
void vTask2(void *pvParameters) {
for (;;) {
// 尝试获取信号量
if (xSemaphoreTake(xBinarySemaphore, portMAX_DELAY) == pdTRUE) {
// 成功获取信号量
// 执行任务
// 释放信号量
xSemaphoreGive(xBinarySemaphore);
}
}
}
int main(void) {
// 创建二进制信号量
xBinarySemaphore = xSemaphoreCreateBinary();
if (xBinarySemaphore != NULL) {
// 创建任务
xTaskCreate(vTask1, "Task 1", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
xTaskCreate(vTask2, "Task 2", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
// 释放初始信号量
xSemaphoreGive(xBinarySemaphore);
// 启动调度器
vTaskStartScheduler();
}
for (;;);
return 0;
}