信号量(Semaphore)是一种用于多线程或多进程环境中控制共享资源访问的同步机制,由荷兰计算机科学家Dijkstra于1965年提出。其核心功能是通过计数器管理资源的可用数量,协调线程/进程的执行顺序,避免竞态条件。以下是关键知识点:
1. 核心原理
信号量维护一个非负整型计数器:
- 计数器>0:表示可用资源数量,线程可申请资源(计数器减1)。
- 计数器=0:资源耗尽,新线程需阻塞等待(通过原子操作保障准确性)。
- V操作(signal):释放资源时计数器加1,唤醒等待线程。
2. 类型区分
- 二进制信号量(Binary Semaphore):计数器仅0或1,等同于互斥锁,用于临界区保护。
- 计数信号量(Counting Semaphore):计数器取值范围≥0,用于管理多实例资源(如线程池、缓冲区槽位)。
3. 实现机制
- 原子操作:PV操作必须为不可分割的指令(如TSL、CAS),防止多线程同时修改计数器导致数据错误。
- 阻塞队列:当资源不足时,操作系统将等待线程挂起并存入队列,释放资源时按优先级/FIFO策略唤醒。
4. 经典应用场景
- 生产者-消费者模型:缓冲区空/满状态通过两个信号量控制,避免越界读写。
- 读写锁实现:用计数器区分读者数量与写者独占,提升并发效率。
- 线程池任务调度:空闲工作线程数量通过信号量动态调整。
5. 扩展知识
- POSIX信号量:Linux中提供`sem_init()`、`sem_wait()`等API,支持进程间同步(命名信号量)。
- 优先级反转问题:高优先级线程因信号量被低优先级线程占用而阻塞,需通过优先级继承协议解决。
- 与互斥锁区别:信号量可跨线程释放,而互斥锁必须由持有者释放;信号量更适用于资源池管理。
6. 潜在风险
- 死锁:多个信号量申请顺序不一致可能导致循环等待(需按固定顺序获取)。
- 资源泄漏:未正确释放信号量会造成资源 starvation(建议使用RAII模式封装)。信号量的合理使用需结合具体场景权衡性能与复杂度。如需更高层次的同步抽象,可考虑管程(Monitor)或条件变量(Condition Variable)。
查看详情
查看详情