freertos学习笔记8--个人自用-第12章 信号量(semaphore)

一:概述

FreeRTOS 提供了信号量和互斥锁,用于任务间的同步和资源共享管理。信号量更偏向于任务同步,而互斥锁用于保护共享资源。

FreeRTOS 中的 信号量 (Semaphore) 是一种用于 任务间通信同步 的机制。

你可以把它简单理解为:一个用来传递状态的“令牌”或“钥匙”。它本质上是一个队列 (Queue),但是这个队列不存储具体的数据,只存储“计数值”(有多少个令牌)。

1. 信号量的三种主要类型

A. 二值信号量 (Binary Semaphore)

B. 计数型信号量 (Counting Semaphore)   

C. 互斥信号量 (Mutex, Mutual Exclusion)

2.信号量的含义

信号量这个名字很恰当:

  • 信号:起通知作用
  • 量:还可以用来表示资源的数量
    • 当"量"没有限制时,它就是"计数型信号量"(Counting Semaphores)
    • 当"量"只有0、1两个取值时,它就是"二进制信号量"(Binary Semaphores)
  • 支持的动作:"give"给出资源,计数值加1;"take"获得资源,计数值减1

3.计数值是什么

二: 信号量的三种主要类型讲解

Take 减一   -1                       Give  加1 +1  

1. 二值信号量 (Binary Semaphore)

2. 计数型信号量 (Counting Semaphore)

3. 互斥信号量 (Mutex / Mutual Exclusion)

三.Give/Take 组合

Take 减一   -1                       Give  加1 +1  


四:信号量函数

做为初学者,信号量函数只需要掌握三类核心操作创建(Create)、获取(Take)、释放(Give),外加一个特别需要注意的中断版(FromISR)

1. 创建

使用信号量之前,要先创建,得到一个句柄(Handle);使用信号量时,要使用句柄来表明使用哪个信号量。 对于二进制信号量、计数型信号量,它们的创建函数不一样:

函数名描述老师的备注
xSemaphoreCreateBinary()创建二值信号量注意: 创建出来默认是“空”的(0),你需要先 Give 一次才能被 Take。
xSemaphoreCreateCounting(...)创建计数信号量需要两个参数:最大计数值(Max)和初始值(Init)。
xSemaphoreCreateMutex()创建互斥量创建出来默认是“满”的(可用),可以直接 Take。

示范代码:

SemaphoreHandle_t mySem; // 1. 定义句柄变量

void main() {
    // 2. 创建
    mySem = xSemaphoreCreateBinary();
    
    // 3. 检查是否创建成功(非常重要!)
    if (mySem == NULL) {
        // 内存不足,创建失败
    }
}

静态之后搜下吧,感觉先不是很重要

代码示范

// 1. 定义句柄(全局变量)
SemaphoreHandle_t myBinarySem = NULL;
SemaphoreHandle_t myCountingSem = NULL;
SemaphoreHandle_t myMutex = NULL;

void main_init_function() {
    
    // --- 创建二值信号量 ---
    myBinarySem = xSemaphoreCreateBinary();
    if (myBinarySem != NULL) {
        // 创建成功,但现在是空的(0),需要先 Give 才能用,或者等中断 Give
        // xSemaphoreGive(myBinarySem); // 如果需要让他默认可用,就手动Give一次
    }

    // --- 创建计数信号量 ---
    // 比如:一个停车场,最多停5辆车,一开始里面也是空的(0辆车)
    myCountingSem = xSemaphoreCreateCounting(5, 0); 

    // --- 创建互斥量 ---
    myMutex = xSemaphoreCreateMutex();
    // 创建成功后,它就是可用的。不需要手动 Give。
}

2 删除

对于动态创建的信号量,不再需要它们时,可以删除它们以回收内存。

vSemaphoreDelete可以用来删除二进制信号量、计数型信号量,函数原型如下:

/*
 * xSemaphore: 信号量句柄,你要删除哪个信号量
 */
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );

3. give/take

二进制信号量、计数型信号量的give、take操作函数是一样的。这些函数也分为2个版本:给任务使用,给ISR使用。列表如下:

在任务中使用在ISR中使用
givexSemaphoreGivexSemaphoreGiveFromISR
takexSemaphoreTakexSemaphoreTakeFromISR

一、 任务版函数 (Task API)

这两个函数只能在任务(Task)中调用,绝对不能在中断(ISR)里用。因为它们允许“阻塞”(也就是睡觉等待),而中断是不能睡觉的。

二、 中断版函数 (ISR API)

中断函数最大的特点是:没有阻塞时间参数(不能等),并且多了一个**“切换上下文”的机制**。

核心机制:pxHigherPriorityTaskWoken 这个参数的变量定义是由你(用户)写的,

代码示范:

假设我们有一个按键中断,当按键按下时,ISR 释放信号量,唤醒一个负责处理按键逻辑的任务(KeyTask)。

步骤 1:定义信号量和任务
SemaphoreHandle_t xKeySemaphore; // 定义信号量句柄

// 在 main 或初始化中创建二进制信号量
xKeySemaphore = xSemaphoreCreateBinary(); 
步骤 2:中断服务程序 (ISR)

这是 ISR 版本的核心写法,请注意 xHigherPriorityTaskWoken 的用法:

void EXTI0_IRQHandler(void)
{
    // 1. 定义一个变量来保存是否需要切换任务的状态,初始化为 pdFALSE
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;

    // 清除中断标志位(具体取决于硬件平台,这里仅为伪代码)
    Clear_IT_Flag();

    // 2. 发送信号量(Give)
    // 告诉 FreeRTOS:“资源有了,如果有任务在等,把它唤醒”
    // 如果唤醒的任务优先级比当前被打断的任务高,xHigherPriorityTaskWoken 会变为 pdTRUE
    xSemaphoreGiveFromISR(xKeySemaphore, &xHigherPriorityTaskWoken);

    // 3. 强制上下文切换
    // 如果 xHigherPriorityTaskWoken 为 pdTRUE,这里会挂起 PendSV 中断
    // 使得 ISR 退出后直接运行高优先级任务,而不是回到原来的低优先级任务
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken); [cite: 4449]
}
步骤 3:接收任务 (Task)

任务中使用普通的阻塞函数等待信号量:

void KeyProcessTask(void *pvParameters)
{
    while(1)
    {
        // 阻塞等待信号量,portMAX_DELAY 表示死等
        if(xSemaphoreTake(xKeySemaphore, portMAX_DELAY) == pdTRUE)
        {
            // 只有当 ISR 执行了 Give 操作,程序才会运行到这里
            printf("按键被按下了,处理业务逻辑...\r\n");
        }
    }
}
4. 总结

在任务中使用在ISR中使用
givexSemaphoreGivexSemaphoreGiveFromISR
takexSemaphoreTakexSemaphoreTakeFromISR

5.问题提问


pxHigherPriorityTaskWoken 这个参数的变量定义是由你(用户)写的

问题1

问题2

问题3

五:对于初学者要掌握的

对于第12章 信号量 (Semaphore),你不需要背下所有的函数参数和复杂的内部机制。作为初学者,你只需要掌握以下 4 个核心点 就能应对 80% 的开发需求:

六:信号量是用于哪些方面的

根据文档第12章的内容,信号量(Semaphore)主要用于解决资源管理任务同步这两个核心问题。

你可以把它理解为一个**“全局计数器”**,用于在多任务之间传递状态或管理数量。具体应用场景分为以下三类:

总结

信号量类型核心作用典型生活例子操作逻辑
计数型资源管理停车场、电影票有票就进,没票排队
计数型事件计数生产流水线生产一个+1,消费一个-1
二进制同步/通知裁判发令枪枪响(Give),运动员跑(Take)
二进制互斥(锁)公用电话亭我用时你别进(注:建议改用Mutex
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值