本文记录FreeRTOS的计数型信号量知识,希望我的分享对你有所帮助!
目录
一、计数型信号量简介
计数型信号量在FreeRTOS中用于管理对共享资源的访问。它允许多任务间同步和互斥,通过设置最大计数值来限制资源的使用。任务可以“获取”信号量,如果计数值大于0,则计数减1并继续执行;如果计数为0,任务会被阻塞直到信号量被释放。信号量被“释放”时,计数值增加,可能会唤醒阻塞的任务。这个机制帮助管理并发任务对有限资源的访问。
我们知道,二值信号量相当于长度为1的队列,那么计数型信号量就是长度大于1的队列,作为用户不需要知道队列里存的是什么,只需要关心队列是否为空就行。
计数型信号量通常被应用于以下场合:
【1】用于事件计数
在事件每次发生的时候,就在事件处理函数中释放信号量,即增加信号量的计数值,其他任务会在此时获取信号量,即信号量计数值减一(此处的信号量值就是结构体成员变量:uxMessagesWaiting),进而根据信号量计数值的变化来处理事件。
在这种场合中创建的计数型信号量初始计数值为0.
【2】资源管理
这时的信号量值表示的是当前资源的可用数量。比如会场剩余的座位数量。一个任务如果想获得资源的使用权,首先必须获取信号量,获取成功后的信号量值就会减一。当信号量的值为0的时候就说明以已经没有资源了。而且,如果一个任务使用完资源后,就一定要释放信号量,释放信号量以后信号量的值就会加一。
在这种场合中信号量的初始值就应该是资源的数量,比如会场的座位数量为100,那么创建信号量的时候信号量的初始值就应该是100.
二、创建计数型信号量
1、动态创建计数型信号量
xSemaphoreCreateCounting
是 FreeRTOS 中用于创建计数型信号量的函数。计数型信号量可以用于任务之间的同步和互斥。SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount, UBaseType_t uxInitialCount);
参数
uxMaxCount
:
- 类型:
UBaseType_t
- 描述: 计数型信号量可以持有的最大计数值。即信号量的“最大值”。
uxInitialCount
:
- 类型:
UBaseType_t
- 描述: 创建信号量时的初始计数值。即信号量的“初始值”。这个值应该小于或等于
uxMaxCount
。返回值
- 成功: 返回一个
SemaphoreHandle_t
类型的信号量句柄。这个句柄用于以后对信号量的操作。- 失败: 返回
NULL
,表示信号量创建失败。创建失败可能是由于内存不足或其他原因。
创建实例:
#include "FreeRTOS.h"
#include "semphr.h"
#include "task.h"
// 定义信号量句柄
SemaphoreHandle_t xSemaphore;
void vTask1(void *pvParameters) {
for (;;) {
// 请求信号量
if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
// 成功获取信号量,执行任务
// ...
// 释放信号量
xSemaphoreGive(xSemaphore);
}
// 延时,模拟任务执行
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void vTask2(void *pvParameters) {
for (;;) {
// 请求信号量
if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
// 成功获取信号量,执行任务
// ...
// 释放信号量
xSemaphoreGive(xSemaphore);
}
// 延时,模拟任务执行
vTaskDelay(pdMS_TO_TICKS(500));
}
}
int main(void) {
// 创建计数型信号量,最大计数为3,初始计数为3
xSemaphore = xSemaphoreCreateCounting(3, 3);
if (xSemaphore == NULL) {
// 信号量创建失败,进行错误处理
// ...
}
// 创建两个任务
xTaskCreate(vTask1, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
xTaskCreate(vTask2, "Task2", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
// 启动调度器
vTaskStartScheduler();
// 启动调度器后不会返回
for (;;);
}
2、静态创建计数型信号量
xSemaphoreCreateCountingStatic()
是 FreeRTOS 提供的一个 API,用于创建一个静态分配的计数型信号量。它的主要功能是用于管理对共享资源的访问。
函数原型:
SemaphoreHandle_t xSemaphoreCreateCountingStatic(
UBaseType_t uxMaxCount,
UBaseType_t uxInitialCount,
StaticSemaphore_t *pxSemaphoreBuffer
);
参数说明:
uxMaxCount
:信号量的最大计数值,即可以支持的最大资源数量。uxInitialCount
:信号量的初始计数值,通常是资源的初始可用数量。pxSemaphoreBuffer
:指向StaticSemaphore_t
结构体的指针,这个结构体用于保存信号量的静态分配数据。返回值:
- 如果成功创建信号量,返回信号量句柄(
SemaphoreHandle_t
)。- 如果创建失败,返回
NULL
。
使用示例:
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
// 定义信号量缓冲区
StaticSemaphore_t xSemaphoreBuffer;
SemaphoreHandle_t xCountingSemaphore;
// 任务函数
void vTask1(void *pvParameters) {
for (;;) {
if (xSemaphoreTake(xCountingSemaphore, portMAX_DELAY) == pdTRUE) {
// 访问共享资源
// 执行任务代码
printf("Task 1 acquired the semaphore.\n");
// 释放共享资源
xSemaphoreGive(xCountingSemaphore);
}
vTaskDelay(pdMS_TO_TICKS(1000)); // 延时1秒
}
}
void vTask2(void *pvParameters) {
for (;;) {
if (xSemaphoreTake(xCountingSemaphore, portMAX_DELAY) == pdTRUE) {
// 访问共享资源
// 执行任务代码
printf("Task 2 acquired the semaphore.\n");
// 释放共享资源
xSemaphoreGive(xCountingSemaphore);
}
vTaskDelay(pdMS_TO_TICKS(1000)); // 延时1秒
}
}
int main(void) {
// 创建计数型信号量
xCountingSemaphore = xSemaphoreCreateCountingStatic(
3, // 最大计数值
3, // 初始计数值
&xSemaphoreBuffer // 静态分配的缓冲区
);
if (xCountingSemaphore == NULL) {
// 处理信号量创建失败的情况
printf("Failed to create semaphore.\n");
return 1;
}
// 创建任务
xTaskCreate(vTask1, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
xTaskCreate(vTask2, "Task2", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
// 启动调度器
vTaskStartScheduler();
// 如果到达此处,说明调度器启动失败
for (;;);
return 0;
}
说明:
xSemaphoreCreateCountingStatic()
被用于创建一个最大计数值为 3 的计数型信号量,初始计数值也为 3。vTask1
和vTask2
是两个任务,它们会尝试获取和释放信号量,模拟对共享资源的访问。xSemaphoreTake()
和xSemaphoreGive()
分别用于获取和释放信号量。vTaskDelay()
用于任务间的延时,以模拟任务的执行时间和避免过于频繁的信号量操作。
三、结语
关于FreeRTOS的计数型信号量就分享到此了,敬请关注,一起加油!
持续更新中~~~