计数信号量相关的 API 函数详解

FreeRTOS 中的计数信号量(Counting Semaphore)用于管理多个资源的访问或事件计数,允许信号量的值在 0 到设定的最大值之间变化。以下是计数信号量相关的 API 函数详解,包括动态和静态创建两种方式。


1. 动态创建计数信号量

函数原型
SemaphoreHandle_t xSemaphoreCreateCounting(
    UBaseType_t uxMaxCount,   // 最大计数值
    UBaseType_t uxInitialCount // 初始计数值
);
  • 功能:动态分配内存并初始化一个计数信号量。
  • 参数
    • uxMaxCount:信号量支持的最大计数值(必须 ≥ uxInitialCount)。
    • uxInitialCount:信号量的初始计数值(0 ≤ uxInitialCountuxMaxCount)。
  • 返回值
    • 成功:返回信号量句柄(SemaphoreHandle_t)。
    • 失败:返回 NULL(内存不足或参数无效时)。
  • 特点
    • 需要确保 FreeRTOS 堆内存足够(通过 configTOTAL_HEAP_SIZE 配置)。
    • 适用于动态分配资源的场景(如管理缓冲区池)。
示例代码
SemaphoreHandle_t xCountingSemaphore = NULL;

void vTaskExample(void) {
    // 动态创建计数信号量:最大5,初始3
    xCountingSemaphore = xSemaphoreCreateCounting(5, 3);
    if (xCountingSemaphore != NULL) {
        // 创建成功
    }
}

2. 静态创建计数信号量

函数原型
SemaphoreHandle_t xSemaphoreCreateCountingStatic(
    UBaseType_t uxMaxCount,       // 最大计数值
    UBaseType_t uxInitialCount,   // 初始计数值
    StaticSemaphore_t *pxSemaphoreBuffer // 静态内存缓冲区
);
  • 功能:使用用户预先分配的静态内存初始化计数信号量。
  • 参数
    • uxMaxCount:最大计数值。
    • uxInitialCount:初始计数值。
    • pxSemaphoreBuffer:指向 StaticSemaphore_t 类型变量的指针(需预先分配内存)。
  • 返回值
    • 成功:返回信号量句柄。
    • 失败:返回 NULL(参数无效时)。
  • 特点
    • 需预先分配 StaticSemaphore_t 结构体内存(通常为全局或静态变量)。
示例代码
StaticSemaphore_t xSemaphoreBuffer;
SemaphoreHandle_t xCountingSemaphore = NULL;

void vTaskExample(void) {
    // 静态创建计数信号量:最大5,初始3
    xCountingSemaphore = xSemaphoreCreateCountingStatic(5, 3, &xSemaphoreBuffer);
    if (xCountingSemaphore != NULL) {
        // 创建成功
    }
}

3. 释放(Give)信号量

函数原型
BaseType_t xSemaphoreGive(SemaphoreHandle_t xSemaphore);
  • 功能:释放信号量,计数值加 1(若未达到最大计数值)。
  • 参数
    • xSemaphore:信号量句柄。
  • 返回值
    • pdPASS:释放成功。
    • pdFAIL:释放失败(计数值已达最大值)。
  • 使用场景:通常在任务中释放信号量(如资源归还)。
中断安全版本
BaseType_t xSemaphoreGiveFromISR(
    SemaphoreHandle_t xSemaphore,
    BaseType_t *pxHigherPriorityTaskWoken
);
  • pxHigherPriorityTaskWoken:标记是否有更高优先级任务被唤醒(需传递到 portYIELD_FROM_ISR())。

4. 获取(Take)信号量

函数原型
BaseType_t xSemaphoreTake(
    SemaphoreHandle_t xSemaphore,
    TickType_t xTicksToWait // 阻塞时间
);
  • 功能:尝试获取信号量,计数值减 1。若计数值为 0,任务可阻塞等待。
  • 参数
    • xSemaphore:信号量句柄。
    • xTicksToWait:阻塞时间(单位:系统节拍),portMAX_DELAY 表示无限等待(需配置 INCLUDE_vTaskSuspend=1)。
  • 返回值
    • pdTRUE:成功获取信号量。
    • pdFALSE:超时或参数无效。
中断安全版本
BaseType_t xSemaphoreTakeFromISR(
    SemaphoreHandle_t xSemaphore,
    BaseType_t *pxHigherPriorityTaskWoken
);

5. 删除信号量

函数原型
void vSemaphoreDelete(SemaphoreHandle_t xSemaphore);
  • 功能:删除信号量并释放内存(仅对动态创建的信号量有效)。
  • 参数
    • xSemaphore:信号量句柄。

使用场景示例

资源池管理
// 初始化一个管理5个缓冲区的信号量(初始全部可用)
SemaphoreHandle_t xBufferSemaphore = xSemaphoreCreateCounting(5, 5);

// 任务获取缓冲区
void vTaskConsumer(void *pvParameters) {
    while (1) {
        if (xSemaphoreTake(xBufferSemaphore, portMAX_DELAY) == pdTRUE) {
            // 成功获取缓冲区,执行操作
            // ...
            // 使用完毕后释放
            xSemaphoreGive(xBufferSemaphore);
        }
    }
}
事件计数
// 初始化一个最大10次事件的信号量(初始0次)
SemaphoreHandle_t xEventSemaphore = xSemaphoreCreateCounting(10, 0);

// 中断中触发事件
void vInterruptHandler(void) {
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    xSemaphoreGiveFromISR(xEventSemaphore, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

// 任务处理累计事件
void vTaskEventHandler(void *pvParameters) {
    while (1) {
        if (xSemaphoreTake(xEventSemaphore, portMAX_DELAY) == pdTRUE) {
            // 处理一个事件(计数值减1)
        }
    }
}

注意事项

  1. 初始值与最大值
    • 初始值应 ≤ 最大值,否则创建失败。
    • 若初始值为 0,表示无可用资源;若初始值等于最大值,表示资源池已满。
  2. 阻塞行为
    • 当信号量计数值为 0 时,调用 xSemaphoreTake 的任务会阻塞。
  3. 优先级反转
    • 计数信号量不解决优先级反转问题,需资源互斥访问时改用互斥量(Mutex)。
  4. 溢出保护
    • 调用 xSemaphoreGive 时若计数值已达最大值,返回 pdFAIL

通过合理使用计数信号量,可以实现资源池管理、事件批量处理、流量控制等功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九层指针

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值