一文带你深度了解FreeRTOS——计数型信号量

 

本文记录FreeRTOS的计数型信号量知识,希望我的分享对你有所帮助!

目录

一、计数型信号量简介 

二、创建计数型信号量

1、动态创建计数型信号量

2、静态创建计数型信号量

三、结语 


一、计数型信号量简介 

计数型信号量在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的计数型信号量就分享到此了,敬请关注,一起加油!

持续更新中~~~

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小小_扫地僧

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

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

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

打赏作者

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

抵扣说明:

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

余额充值