内部实现
信号量sem
POSIX sem_t
信号量的用处
- 需要计数任务时,因为信号量可以统计数量
- 当中任务通知用(实际上FreeRTOS的任务通知就是轻量化的二进制信号量(可以替代掉二进制信号量))
- 当互斥锁用(但是不推荐,因为无法解决优先级反转的问题)
事件evt
pthread_cond_t+pthread_mutex_t主要依靠条件变量实现
使用区别
- 信号量需要计数
- 事件只有两种状态
不需要信号量计数的情况下
区别1:先Post(释放)后Pend(请求),结果不同
信号量(sem_post):Post 会累加计数,即使没人等也不丢
计数0→1 → 计数1→0,立即返回成功 ✓
OS_SemPost 底层是 sem_post,它会把信号量的值从0加到1,这个值会保留下来,后续 sem_wait 来了直接拿走,不会阻塞。
事件(pthread_cond_signal):Post 时没人在等,signal 就丢了
无人等待,signal丢失 → 永远阻塞 ✗
OS_EvtPost 底层是 pthread_cond_signal,它只是唤醒当前正在 pthread_cond_wait 上的线程。如果那一刻没有线程在 wait,这个 signal 就消失了,什么也没留下。
区别2:事件存在"虚假唤醒"
pthread_cond_wait 在 Linux 上可能没有人 Post 也会自己醒来(操作系统实现层面的已知问题),所以条件变量的正确用法必须配合 while 循环和条件变量检查:
条件变量(pthread_cond)的不可替代之处
在上面的描述过程当中,好像感觉pthread_cond挺没有用的,实则不然。
广播唤醒
信号量的 sem_post 每次只能让一个 sem_wait 返回。如果想唤醒5个线程,必须 sem_post 5次。
条件变量的 pthread_cond_broadcast 可以一次唤醒所有正在等待的线程。等的是条件,不是信号
信号量只能告诉你"有人 Post 了",但不知道具体是什么条件满足了。
条件变量的真正用法是:等待某个条件为真,而不是等待一个信号。
信号量思维:等一个通知 → 通知来了就往下走
条件变量思维:等一个条件 → 条件满足才往下走,不满足继续等
- 信号丢失的优势
条件变量:3次上报 → 只保留最新1次通知 → 处理线程醒来1次,只处理最新数据