-
1. 信号量(Semaphore)
原理与结构
-
核心机制:
信号量通过计数器(value
)表示可用资源数量。- 获取信号量(
rt_sem_take
):若value > 0
,value
减1并返回成功;否则线程挂起等待。 - 释放信号量(
rt_sem_release
):若有等待线程,唤醒队列首线程;否则value
加1,最大值为RT_SEM_VALUE_MAX
(65535)。
- 获取信号量(
-
数据结构:
struct rt_semaphore { struct rt_ipc_object parent; // 继承自IPC对象 rt_uint16_t value; // 信号量计数器 rt_uint16_t reserved; // 保留字段 };
- 资源池管理:
- 如停车场模型,初始值设为总资源数(如车位数量),线程获取/释放资源时计数器增减。
- 线程同步:
初始值设为0,线程A等待信号量,线程B完成任务后释放,触发A执行。 - 中断与线程同步:
中断服务函数释放信号量,通知线程处理异步事件。
代码示例
// 动态创建信号量(初始值1,FIFO队列)
rt_sem_t sem = rt_sem_create("sem_test", 1, RT_IPC_FLAG_FIFO);
// 获取信号量(永久等待)
rt_sem_take(sem, RT_WAITING_FOREVER);
// 释放信号量
rt_sem_release(sem);
-
源码拆解分析
rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t time)
rt_sem_take
是RT-Thread中用于获取信号量的核心函数,其核心逻辑如下: -
检查信号量可用性:若信号量值(
sem->value
)大于0,直接获取(value--
)并返回成功。 -
处理不可用场景:若信号量为0且
time=0
,立即返回超时错误;否则挂起当前线程,并启动超时定时器(若time>0
)。 -
线程调度与唤醒:挂起线程后触发调度器切换,等待其他线程释放信号量或超时唤醒
2. 互斥信号量(Mutex)
原理与结构
-
核心机制:
互斥量用于严格互斥访问共享资源,支持优先级继承防止优先级翻转。- 优先级继承:当低优先级线程持有互斥量时,若高优先级线程等待,临时提升持有者优先级至等待线程的最高优先级。
- 递归持有:同一线程可多次获取互斥量(
hold
计数),需相同次数释放。
-
数据结构:
-
struct rt_mutex { struct rt_ipc_object parent; // 继承自IPC对象 rt_uint16_t value; // 互斥量状态(0或1) rt_uint8_t original_priority; // 持有者原始优先级 rt_uint8_t hold; // 递归持有计数 struct rt_thread *owner; // 当前持有线程 };
应用场景
- 共享资源保护:
如共享内存或硬件外设访问,确保同一时间仅一个线程操作。 - 防止优先级翻转:
通过优先级继承避免低优先级线程阻塞高优先级线程。
示例代码
// 动态创建互斥量(优先级队列)
rt_mutex_t mutex = rt_mutex_create("mutex_test", RT_IPC_FLAG_PRIO);
// 获取互斥量(永久等待)
rt_mutex_take(mutex, RT_WAITING_FOREVER);
// 释放互斥量
rt_mutex_release(mutex);
源码拆解分析
rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t time)
rt_mutex_take
是RT-Thread中用于获取互斥量的核心函数,其设计目标是通过优先级继承解决优先级翻转问题,同时支持递归持有和严格互斥访问。核心逻辑如下:
- 递归持有检查:若当前线程已持有互斥量,增加递归计数(
hold
)并直接返回成功。 - 互斥量可用性判断:若互斥量未被占用(
value > 0
),设置持有者并更新优先级;否则挂起线程并触发优先级继承。 - 超时与唤醒机制:若指定
time > 0
,启动定时器并挂起线程,超时或互斥量释放后唤醒线程。
-
3.核心区别对比
特性 信号量 互斥量 计数器范围 0~65535(支持资源池) 仅0或1(二进制互斥) 优先级继承 不支持 支持,避免优先级翻转 递归持有 不支持 支持( hold
计数)释放者身份限制 任意线程或中断均可释放 必须由持有者释放 适用场景 同步、资源池管理 严格互斥访问,需避免优先级反转的共享资源保护