8 信号量
信号量
1. 什么是信号量
在 FreeRTOS 中,信号量(Semaphore) 是一种用于任务之间或任务与中断之间进行同步与资源管理的机制。
可以把信号量理解为一种“通行证”或“标志”:
- 有信号量:表示条件满足,任务可以继续执行
- 没有信号量:表示条件还不满足,任务需要等待
信号量本身不是用来传递具体数据的,而是用来表示:
- 某个事件是否发生
- 某个资源是否可用
- 某个任务是否可以继续运行
2. 信号量的核心作用
FreeRTOS 中信号量主要有两个核心作用:
2.1 同步
用于任务与任务之间、任务与中断之间的同步。
例如:
- 任务 A 完成某项工作后,通知任务 B 开始执行
- 某个中断发生后,唤醒等待处理该事件的任务
2.2 资源访问控制
用于协调多个任务对共享资源的访问,避免资源冲突。
例如:
- 多个任务同时访问串口
- 多个任务同时访问 I2C、SPI、LCD
- 多个任务同时操作同一个全局变量
3. 如何理解信号量
可以把信号量想象成一个装“令牌”的盒子。
- 任务想继续执行时,就去获取令牌
- 如果盒子里有令牌,任务就拿走一个并继续执行
- 如果盒子里没有令牌,任务就需要阻塞等待
- 当其他任务或中断释放令牌后,等待的任务就有机会继续执行
4. FreeRTOS 中信号量的类型
4.1 二值信号量(Binary Semaphore)
二值信号量只有两种状态:
- 0:没有信号量
- 1:有信号量
它适合用于:
- 任务同步
- 中断通知任务
特点
- 本质上表示“有”或“没有”
- 常用于事件通知
- 常见于中断服务函数与任务之间的配合
典型场景
- 按键中断触发一次
- 在中断中释放一次二值信号量
- 任务获取到信号量后处理按键事件
4.2 计数信号量(Counting Semaphore)
计数信号量的值可以大于 1,用来表示:
- 某类资源当前有多少个
- 某个事件累计发生了多少次
特点
- 本质上是一个计数器
- 可以记录多个资源或多个事件次数
典型场景
- 一个资源池中有 3 个相同资源
- 最多允许 3 个任务同时获取
- 每获取一次,计数减 1
- 每释放一次,计数加 1
4.3 互斥量(Mutex)
互斥量可以看作一种特殊的信号量,但它主要用于共享资源互斥访问。
特点
- 更适合保护临界资源
- 具有优先级继承机制
- 一般是谁获取,谁释放
典型场景
- 多个任务访问同一个串口
- 多个任务访问同一个全局变量
- 多个任务访问同一个硬件外设
注意
虽然互斥量也属于同步对象,但它和普通信号量的使用目的不同:
- 二值信号量 更偏向“同步通知”
- 互斥量 更偏向“资源保护”
5. 信号量的基本操作
在 FreeRTOS 中,信号量最核心的操作有两个:
5.1 获取信号量
任务尝试获得一个信号量。
结果有三种可能:
- 获取成功,任务继续执行
- 获取失败,立即返回
- 获取失败后阻塞等待,直到超时或获取成功
获取信号量的本质就是:
检查当前是否满足继续执行的条件。
5.2 释放信号量
任务或中断把信号量释放出去,表示:
- 某个事件已经发生
- 某个资源已经使用完毕,可以给其他任务用了
释放信号量的本质就是:
告诉系统:现在可以唤醒等待者了。
6. 信号量的常见应用场景
6.1 任务与任务同步
例如:
- 任务 A 负责采集数据
- 任务 B 负责处理数据
- A 采集完成后释放信号量
- B 获取到信号量后开始处理
这类应用中,信号量起到的是“通知”和“同步”的作用。
6.2 中断与任务同步
例如:
- 外部按键中断发生
- 中断服务函数中释放信号量
- 处理任务获取到信号量后执行按键处理逻辑
这样做的原因是:
- 中断服务函数要尽量短小
- 复杂处理应放到任务中执行
所以信号量常用于把中断中的事件“转交”给任务处理。
6.3 共享资源保护
例如多个任务都要访问串口:
- 任务先获取互斥量
- 获取成功后才能访问串口
- 访问完成后释放互斥量
- 其他任务再继续访问
这样可以避免多个任务同时操作一个资源,导致数据混乱或系统异常。
7. 信号量与队列的区别
很多初学者容易把信号量和队列混淆,它们的区别可以这样理解:
7.1 队列
队列主要用于:
- 传递数据
- 在任务之间交换具体内容
例如:
- 发送一个整数
- 发送一个结构体
- 发送一组传感器数据
7.2 信号量
信号量主要用于:
- 传递状态
- 通知事件
- 控制资源访问
例如:
- 告诉任务“数据到了”
- 告诉任务“可以执行了”
- 告诉任务“资源空出来了”
7.3 一句话区分
- 队列:传数据
- 信号量:传状态、传事件
可以记为:
信号量告诉你“可以开始做了”,队列告诉你“具体做什么内容”。
8. 使用信号量时的理解重点
学习 FreeRTOS 信号量时,要重点理解以下几点:
8.1 信号量不适合传递复杂数据
它主要表示“有无”“多少”“是否可用”,而不是传递具体内容。
8.2 同步和互斥是两个不同概念
- 同步:强调任务之间的先后配合
- 互斥:强调共享资源同一时刻只能被一个任务使用
8.3 保护资源优先考虑互斥量
如果目的是保护共享资源,通常应优先使用互斥量,而不是普通信号量,因为互斥量支持优先级继承。
9. 信号量的本质总结
从本质上来说,FreeRTOS 中的信号量是一种由内核提供的同步对象,用于实现:
- 任务与任务之间的同步
- 中断与任务之间的同步
- 多任务对共享资源的协调访问
它不负责保存复杂数据,而是负责:
- 通知
- 等待
- 唤醒
- 资源控制
10. 总结
FreeRTOS 中的信号量可以总结为:
信号量是一种用于任务同步和资源管理的机制,本质上用于表示事件是否发生、资源是否可用,以及任务是否可以继续执行。
可以进一步记忆为:
- 二值信号量:像开关,适合同步通知
- 计数信号量:像计数器,适合管理多个资源或统计事件次数
- 互斥量:像带钥匙的锁,适合保护共享资源
11. 面试式简短回答
如果面试官问“什么是 FreeRTOS 中的信号量”,可以这样回答:
FreeRTOS 中的信号量是一种同步机制,主要用于任务间同步、任务与中断同步以及共享资源访问控制。它本身不传递具体数据,而是通过获取和释放来表示某个事件是否发生或某个资源是否可用。常见的有二值信号量、计数信号量和互斥量,其中互斥量更适合保护共享资源。
