计数型信号量(Count Semaphore)

计数型信号量(Count Semaphore)

计数型信号量 好比一个停车场,停车场里面有 10 个车位,当车进入的时候,车位被占用一个,计数器减一;车开出去的时候,车位被是释放,计数器加一。这就是计数型的信号量。当信号量为零时,则表名停车场内已经没有可用车位。 官方函数文档 4.11 uxSemaphoreGetCount() [[FreeRT

计数型信号量

好比一个停车场,停车场里面有 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:信号量成功创建。

注意事项:

  • 计数型信号量一般在两种情况下使用:
    1. 计算事件次数(Counting Events):
      在这种情况,每次事件发生时,事件处理任务都会“发出( Give )”信号量,而处理任务每次都会“获取( Take )”信号量。
      (event handler -> Give, task handler -> take)
      信号量的计数每次会在“发出( Give )”时增加;会在每次“获取( Take )”时减少。
      因此,计数值是已发生事件数和已处理事件数之间的差值。
      用于计数事件的信号量的初始值应该为零,因为在创建信号之前不会对任何事件计数。
    2. 资源管理(Resource management):
      在这种情况下,计数器的值代表资源可用数量。
      为了获取对资源的控制权,任务必须首先“获取( Take )”信号量。“获取”操作会减少信号量的值,当计数值到达 0 时,代表没有资源可用,所以再进行“获取”操作会失败。
      当任务完成并拥有资源时,它必须“发出( Give )”个信号量。“发出”操作会增加信号量的值,为了保证未来的“获取”操作成功执行。
      创建资源管理型的信号量,应该在一开始将最大值定义为资源库存量。

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);
}

示例输出

16. 计数型信号量(Count Semaphore)-20240616004350117.webp

程序输出结果表明,停车场运行正常,车停满之后就等待位置空出来,新的车再进去。

Comment