计数型信号量
好比一个停车场,停车场里面有 10 个车位,当车进入的时候,车位被占用一个,计数器减一;车开出去的时候,车位被是释放,计数器加一。这就是计数型的信号量。当信号量为零时,则表名停车场内已经没有可用车位。
官方函数文档
4.11 uxSemaphoreGetCount()
[[FreeRTOS_Reference_Manual_V10.0.0.pdf#page=234&selection=2,0,4,21|FreeRTOS_Reference_Manual_V10.0.0, page 234]]
4.4 xSemaphoreCreateCounting()
[[FreeRTOS_Reference_Manual_V10.0.0.pdf#page=218&selection=2,0,4,26|FreeRTOS_Reference_Manual_V10.0.0, page 218]]
xSemaphoreCreateCounting()
#include "FreeRTOS.h"
#include "semphr.h"
SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount );
函数说明:
- 创建一个计数型信号量,返回一个信号量句柄。
- RAM needed.
参数:
uxMaxCount:
计数型信号量的计数最大值。uxInitialCount:
创建信号量时赋予的计数值。
返回值:
NULL:
如果没有足够的堆内存,则信号量创建失败。Any other value:
信号量成功创建。
注意事项:
- 计数型信号量一般在两种情况下使用:
- 计算事件次数(Counting Events):
在这种情况,每次事件发生时,事件处理任务都会“发出( Give )”信号量,而处理任务每次都会“获取( Take )”信号量。
(event handler -> Give, task handler -> take
)
信号量的计数每次会在“发出( Give )”时增加;会在每次“获取( Take )”时减少。
因此,计数值是已发生事件数和已处理事件数之间的差值。
用于计数事件的信号量的初始值应该为零,因为在创建信号之前不会对任何事件计数。 - 资源管理(Resource management):
在这种情况下,计数器的值代表资源可用数量。
为了获取对资源的控制权,任务必须首先“获取( Take )”信号量。“获取”操作会减少信号量的值,当计数值到达 0 时,代表没有资源可用,所以再进行“获取”操作会失败。
当任务完成并拥有资源时,它必须“发出( Give )”个信号量。“发出”操作会增加信号量的值,为了保证未来的“获取”操作成功执行。
创建资源管理型的信号量,应该在一开始将最大值定义为资源库存量。
- 计算事件次数(Counting Events):
uxSemaphoreGetCount()
#include "FreeRTOS.h"
#include "semphr.h"
UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore );
函数说明:
- 取得计数型信号量的数目。二进制信号量(Binary Semaphore)只能拥有一个计数( 1 或 0)。技术型信号量拥有一个可以从 0 到 无限 的计数。
- 每次取得一个信号量,则计数型信号量的值会减一。
参数:
xSemaphore:
信号量的句柄。
返回值:
- 返回信号量句柄中信号的计数。
示例代码
此代码模拟了一个停车场(资源管理型),两个任务函数分别模拟车进车出,用信号量当前值表示为停车场剩余空间,用信号量最大值表示停车场总共空间。
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_flash.h"
#include "esp_system.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
static SemaphoreHandle_t semaphore_handle;
void car_in(void *pvPara)
{
int empty_space = 0;
while (true) {
// 获取停车场剩余空间
empty_space = uxSemaphoreGetCount(semaphore_handle);
printf("empty_space = %d\n", empty_space);
// 从停车场拿走一个空间用来停车 ( Take )
xSemaphoreTake(semaphore_handle, portMAX_DELAY);
if (semaphore_state == pdPASS) {
printf("[CAR IN]: One car in.\n");
} else {
printf("[CAR IN]: No more empty space.\n");
}
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void car_out(void *pvPara)
{
while (true) {
vTaskDelay(pdMS_TO_TICKS(6000));
// 车要走了,所以给停车场还回去一个车位( Give )
xSemaphoreGive(semaphore_handle);
printf("[CAR OUT]: One car out\n");
}
}
void app_main(void)
{
// 创建技术型信号量,初始值为10,最大值为10。即 停车场初始有 10 个空位,一共有 10 个车位
semaphore_handle = xSemaphoreCreateCounting(10, 10);
xTaskCreate(car_in, "Car In", 2048, (void *)semaphore_handle, 1, NULL);
xTaskCreate(car_out, "car Out", 2048, (void *)semaphore_handle, 1, NULL);
}
示例输出
程序输出结果表明,停车场运行正常,车停满之后就等待位置空出来,新的车再进去。