C++中semaphore的使用:多线程同步利器

最新面试资源推荐:
🔵 2025年Java面试宝典下载
提取码:9b3g(建议保存备用)
一、信号量是什么?
信号量(semaphore)本质是种计数器,用来控制多线程/多进程对共享资源的访问。想象成停车场的剩余车位指示牌:车位满时(计数器=0)新车要等待,有车离开(计数器+1)才放行新车进入。
二、为什么需要semaphore?
在C++并发编程中,当多个线程竞争共享资源(如内存块、连接池)时,直接访问会导致数据竞争。semaphore通过acquire()(获取信号量)和release()(释放信号量)两个原子操作实现:
// 伪代码示例
sem.acquire(); // 等待信号量>0,然后减1
// 访问临界资源
sem.release(); // 信号量加1
三、C++20中的semaphore使用
C++20终于将semaphore纳入标准库(需包含<semaphore>头文件),主要提供两种类型:
- std::counting_semaphore:通用计数信号量
std::counting_semaphore<10> sem(5); // 最大10,初始5 sem.acquire(); // 等待并减少计数 sem.release(); // 增加计数 - std::binary_semaphore:二元信号量(本质是counting_semaphore<1>的别名)
四、经典应用场景
-
生产者-消费者模型
生产者**release()信号量(增加产品),消费者acquire()**信号量(消耗产品):std::counting_semaphore empty(10); // 空缓冲区数量 std::counting_semaphore full(0); // 满缓冲区数量 // 生产者 empty.acquire(); // 等待空位 produce_item(); full.release(); // 通知有新数据 // 消费者 full.acquire(); // 等待数据 consume_item(); empty.release(); // 释放空位 -
线程池限流
初始化信号量=最大线程数,任务执行前acquire(),结束后release(),避免资源过载。 -
读写锁替代方案
通过组合多个semaphore实现更灵活的读写控制。
五、注意事项与陷阱
- 死锁风险:
acquire()/release()必须成对出现,且顺序不能颠倒 - 优先级反转:高优先级线程因等待低优先级线程持有的semaphore被阻塞
- C++版本兼容:确认编译器支持C++20(GCC>=10, Clang>=13)

面试实战技巧:
当面试官问“如何用C++实现多线程同步”时,除了mutex和condition_variable,一定要提到semaphore!可这样分层回答:
- 先解释semaphore的计数器模型
- 对比与mutex的区别(信号量无所有者,可跨线程release)
- 举例生产者-消费者场景
- 提及C++20标准化进展
💡 小福利:
准备面试需要海量题库?通过面试鸭返利网购买会员可返利25元!覆盖C++、Java、算法高频考点,点击直达→ mianshiyafanli.com

(点击上方图片进入官网)


