std::semaphore是C++20标准库中新增的同步原语,属于信号量类型,主要用于控制同时访问某一资源或资源池的线程数量,避免过多线程同时操作共享资源引发问题。它内部维护了一个计数器,通过对计数器的增减操作来实现线程的同步与资源访问控制。

std::semaphore的核心特性
std::semaphore有两种模板特化形式,分别是std::counting_semaphore<std::ptrdiff_t>和std::binary_semaphore,其中std::binary_semaphore本质是计数器最大值仅为1的计数信号量,等价于std::counting_semaphore<1>。其核心操作包含两个部分:
- acquire操作:尝试减少信号量的计数器,如果计数器大于0则操作成功,计数器减1;如果计数器等于0则当前线程阻塞,直到计数器变为大于0。
- release操作:增加信号量的计数器,通常会唤醒一个等待中的线程。
如何用std::semaphore控制并发资源数
控制并发资源数的核心思路是:将信号量的初始计数器设置为允许同时访问资源的最大线程数,每个线程访问资源前执行acquire操作,访问完成后执行release操作,这样就能保证同时只有指定数量的线程可以访问资源。
基础使用示例
假设我们有一个最多允许3个线程同时访问的共享资源,使用std::semaphore的实现如下:
#include <iostream>
#include <thread>
#include <vector>
#include <semaphore>
#include <chrono>
// 初始化信号量,最大并发数为3
std::counting_semaphore<3> sem(3);
void access_resource(int thread_id) {
// 获取信号量,计数器减1,若计数器为0则阻塞等待
sem.acquire();
std::cout << "线程" << thread_id << "开始访问共享资源" << std::endl;
// 模拟资源访问耗时
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "线程" << thread_id << "结束访问共享资源" << std::endl;
// 释放信号量,计数器加1,唤醒等待线程
sem.release();
}
int main() {
std::vector<std::thread> threads;
// 创建10个线程尝试访问资源
for (int i = 0; i < 10; i++) {
threads.emplace_back(access_resource, i);
}
// 等待所有线程执行完成
for (auto& t : threads) {
t.join();
}
return 0;
}
上述代码中,信号量初始值为3,因此同一时间最多只有3个线程可以执行到资源访问的逻辑,其余线程会在sem.acquire()处阻塞,直到有线程执行sem.release()释放信号量。
超时控制场景
std::semaphore还提供了带超时的acquire操作try_acquire_for和try_acquire_until,可以避免线程无限阻塞。例如我们设置线程等待信号量最多等待1秒,超时则放弃访问:
#include <iostream>
#include <thread>
#include <semaphore>
#include <chrono>
std::counting_semaphore<2> sem(2);
void try_access(int thread_id) {
// 尝试获取信号量,最多等待1秒
if (sem.try_acquire_for(std::chrono::seconds(1))) {
std::cout << "线程" << thread_id << "成功获取信号量,访问资源" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(3));
sem.release();
} else {
std::cout << "线程" << thread_id << "等待超时,放弃访问资源" << std::endl;
}
}
int main() {
std::thread t1(try_access, 1);
std::thread t2(try_access, 2);
std::thread t3(try_access, 3);
t1.join();
t2.join();
t3.join();
return 0;
}
std::semaphore与其他同步工具的差异
| 工具类型 | 核心用途 | 计数器特性 |
|---|---|---|
| std::semaphore | 控制并发访问资源的数量 | 计数器可自定义最大值,支持增减操作 |
| std::mutex | 保证互斥访问共享资源 | 无计数器,仅支持锁定和释放两种状态 |
| std::condition_variable | 线程间的条件等待与唤醒 | 无内置计数器,需配合互斥锁和自定义条件使用 |
使用注意事项
- std::semaphore是C++20新增特性,使用时需要编译器支持C++20及以上标准,编译时需要添加对应的标准参数,如
-std=c++20。 - release操作的调用次数不能超过信号量的最大计数器值,否则会导致未定义行为。
- 信号量的acquire和release需要在同一个逻辑流程中配对使用,避免出现信号量泄漏,导致其他线程永久阻塞。
std::semaphoreC++并发控制信号量修改时间:2026-06-16 02:30:34