当前位置: 首页 > news >正文

嵌入式|RTOS教学——FreeRTOS基础4:信号量

在嵌入式实时操作系统(如 FreeRTOS、RT-Thread 等)中,信号量(Semaphore) 是一种用于任务同步资源管理的核心机制,本质是一个 “带计数的标志”,通过对计数器的 “获取” 和 “释放” 操作,实现多任务间的协作与冲突控制。

简单来说,信号量可以理解为:

  • 一个 “通行证”:任务需要获得通行证才能执行某个操作(如访问共享资源);
  • 一个 “通知器”:任务完成后释放通行证,通知其他等待的任务可以开始执行。

一、信号量的核心组成

信号量的核心是一个计数器和一个等待队列

  • 计数器(count):记录可用的 “资源数量” 或 “通知次数”,取值范围由具体 RTOS 定义(通常为非负整数)。
  • 等待队列(wait queue):当信号量计数器为 0 时,试图获取信号量的任务会进入这个队列,进入 “阻塞态” 等待,直到有其他任务释放信号量。

二、信号量的两种核心类型

根据计数器的特性,信号量主要分为两类,适用场景不同:

1. 二进制信号量(Binary Semaphore)

  • 特性:计数器只能为 0 或 1(类似 “开关”)。

  • 核心作用任务同步(通知事件发生)。

  • 工作流程

    1. 初始状态:计数器为 0(信号量 “未释放”)。
    2. 任务 A 完成某个操作后,调用 “释放信号量” 接口,计数器变为 1(发出 “事件完成” 通知)。
    3. 任务 B 调用 “获取信号量” 接口,若计数器为 1,则获取成功(计数器变回 0),开始执行后续操作;若计数器为 0,则任务 B 进入阻塞态,等待任务 A 释放信号量。
  • 示例场景
    传感器采集任务(A)完成一次数据采集后,释放二进制信号量;数据处理任务(B)一直等待该信号量,获取成功后立即处理新采集的数据(实现 “采集完成→处理” 的同步)。

2. 计数信号量(Counting Semaphore)

  • 特性:计数器可以是 0 到 N 之间的整数(N 为最大计数,创建时指定)。

  • 核心作用资源管理(控制多个任务对有限资源的访问)。

  • 工作流程

    1. 初始状态:计数器为 N(表示有 N 个资源可用)。
    2. 任务获取信号量:计数器减 1(占用一个资源);若计数器为 0,任务进入阻塞态等待。
    3. 任务释放信号量:计数器加 1(释放一个资源);若有任务在等待队列中,唤醒其中一个任务(通常是优先级最高的)。
  • 示例场景
    系统有 2 个串口资源,创建计数信号量时初始计数设为 2。3 个任务需要使用串口时:前 2 个任务能成功获取信号量(计数器变为 0),第 3 个任务进入阻塞态;当任意一个任务用完串口并释放信号量(计数器变为 1),第 3 个任务被唤醒,获取信号量后使用串口。

三、信号量的核心操作(以 FreeRTOS 为例)

信号量的使用围绕 “创建→获取→释放” 三个核心操作,FreeRTOS 提供了简洁的接口:

操作函数接口(FreeRTOS)功能说明
创建xSemaphoreCreateBinary()创建二进制信号量(初始计数为 0)。
xSemaphoreCreateCounting()创建计数信号量(需指定最大计数和初始计数,如 xSemaphoreCreateCounting(5, 3) 表示最大 5 个资源,初始 3 个可用)。
获取xSemaphoreTake()任务中获取信号量:计数器减 1,若计数器为 0 则阻塞(阻塞时间可设置);成功返回 pdPASS
xSemaphoreTakeFromISR()中断中获取信号量(不阻塞,仅用于特殊场景,通常不推荐在中断中获取)。
释放xSemaphoreGive()任务中释放信号量:计数器加 1,若有等待任务则唤醒;成功返回 pdPASS
xSemaphoreGiveFromISR()中断中释放信号量(中断安全版本)。

四、信号量 vs 消息队列:核心区别

信号量和消息队列都能实现任务间通信,但定位不同:

  • 信号量:更侧重 “事件同步” 或 “资源计数”,不传递具体数据(仅传递 “是否可用” 的状态)。
    例:用信号量通知 “按键被按下”,但不传递 “按下的是哪个键” 的信息。
  • 消息队列:更侧重 “数据传递”,可以携带具体数据(如温度值、命令字)。
    例:用队列传递 “按键值 = KEY1”,接收方知道具体是哪个键被按下。

五、典型应用场景

  1. 中断与任务同步
    外部中断(如按键触发)发生时,在中断服务函数中用 xSemaphoreGiveFromISR() 释放二进制信号量;任务中用 xSemaphoreTake() 等待该信号量,获取成功后处理中断事件(避免在中断中执行复杂逻辑)。

  2. 限制共享资源访问
    多个任务需要访问同一块 LCD 屏(唯一资源),用二进制信号量控制:任务使用 LCD 前获取信号量(确保独占),用完后释放,避免多个任务同时刷新 LCD 导致显示混乱。

  3. 任务间顺序控制
    系统启动时,初始化任务(A)需要先初始化外设,完成后释放信号量;其他任务(B、C、D)必须等待该信号量才能运行(确保外设就绪后再操作)。

  4. 限流控制
    某传感器最大支持每秒被读取 10 次,用计数信号量(初始计数 10,最大 10):每次读取前获取信号量(计数减 1),1 秒后定时任务释放 10 个信号量(恢复计数),避免读取频率过高损坏硬件。

六、使用注意事项

  1. 避免死锁
    若任务 A 持有信号量 S1 并等待信号量 S2,任务 B 持有 S2 并等待 S1,会导致两者永久阻塞(死锁)。需统一任务获取信号量的顺序(如按信号量地址从小到大)。

  2. 中断中谨慎操作
    中断中只能释放信号量(用 xSemaphoreGiveFromISR()),禁止获取信号量(可能阻塞,违反中断 “快速执行” 原则)。

  3. 合理设置阻塞时间
    获取信号量时,阻塞时间过短可能导致任务频繁失败;过长可能影响实时性。根据业务需求设置(如非关键任务设短时间,关键任务设 portMAX_DELAY 永久等待)。

  4. 二进制信号量 vs 互斥锁
    二进制信号量用于 “同步”,互斥锁(Mutex)用于 “独占资源”(带优先级继承机制,避免优先级反转)。若要保护共享资源,优先用互斥锁而非二进制信号量。

总结

信号量是 RTOS 中实现任务协作与资源控制的 “轻量级工具”,通过简单的计数机制,解决了多任务环境下的同步、互斥和限流问题。核心是理解:

  • 二进制信号量:“0 或 1” 的开关,用于事件通知;
  • 计数信号量:“0 到 N” 的计数器,用于资源管理。

结合具体场景选择合适的信号量类型,并注意避免死锁和中断使用禁忌,就能充分发挥其作用。


文章转载自:

http://siSCXlxt.wrcym.cn
http://FyyTU9NX.wrcym.cn
http://eenHycLU.wrcym.cn
http://ntL2OaIt.wrcym.cn
http://5bMpwtwm.wrcym.cn
http://S66Su00D.wrcym.cn
http://78kflMb3.wrcym.cn
http://e23eQYAF.wrcym.cn
http://kQsRG5kF.wrcym.cn
http://aHZgFYoj.wrcym.cn
http://UmJ9uLij.wrcym.cn
http://TbbzcriL.wrcym.cn
http://GP186zIO.wrcym.cn
http://AZIbIHmm.wrcym.cn
http://lFGy7gie.wrcym.cn
http://nLkl8vw9.wrcym.cn
http://RCqTUrLe.wrcym.cn
http://KL6qX6Nz.wrcym.cn
http://0nUbkd06.wrcym.cn
http://HHxQlqOV.wrcym.cn
http://lXEOqrMr.wrcym.cn
http://AjkexwJK.wrcym.cn
http://OgsQx35a.wrcym.cn
http://piM64Xbz.wrcym.cn
http://kKCpK5nG.wrcym.cn
http://zoD4bdl0.wrcym.cn
http://2OAz5ewu.wrcym.cn
http://tZ1aaSPG.wrcym.cn
http://zIymhVeU.wrcym.cn
http://3VLoX3Bk.wrcym.cn
http://www.dtcms.com/a/364753.html

相关文章:

  • android集成unity后动态导入 assetsBundle
  • 小米fastboot不能被电脑识别但手机正常使用模式时能被电脑识别
  • 【小白笔记】移动硬盘为什么总比电脑更容易满?
  • Spring Boot 全局异常处理问题分析与解决方案
  • 代码质量保障:使用Jest和React Testing Library进行单元测试
  • HTML元素周期表
  • react的 hooks 是如何存储的
  • 190页经典PPT | 某科技集团数字化转型SAP解决方案
  • 【算法--链表】141.环形链表(通俗讲解链表中是否有环)
  • VUE的中 computed: { ...mapState([‘auditObj‘]), }写法详解
  • 工业相机为啥丢包?黑条 / 撕裂的原因 + 解决办法,一看就懂
  • LeetCode 1537.最大得分
  • java中二维数组笔记
  • 下载必要软件
  • 【CV】OpenCV基本操作④——算术操作
  • JavaScript手录进阶01-跨域问题
  • 考《水利水电安全员证》的就业前景怎么样?
  • OVITO3.13.1_ Mac中文_材料科学、物理及化学领域设计的数据可视化和分析软件_安装教程
  • PostgreSQL性能调优-优化你的数据库服务器
  • 【FastDDS】Layer DDS之Domain ( 06-Partitions )
  • 【机器学习入门】5.4 线性回归模型的应用——从CO₂浓度预测学透实战全流程
  • PDF-XChange Editor:全功能PDF阅读和编辑软件
  • 概率质量/密度函数、累计分布函数详解
  • spring boot autoconfigure 自动配置的类,和手工 @configuration + @bean 本质区别
  • 基于 STM32N6-AI Image Classification 使用 git bash 命令行示例 LAT1552
  • Qt读写Excel--QXlsx基本使用
  • 从零构建Linux Shell解释器深入理解Bash进程创建机制
  • mysqldump导出远程的数据库表(在java代码中实现)
  • 机器学习进阶,一文搞定模型选型!
  • PPI网络与TF-miRNA调控网络的实现方法(基于《列腺癌研究.pdf》)