@@ -1177,6 +1177,57 @@ int main() {
1177
1177
1178
1178
信号量常用于发信/提醒而非互斥,通过初始化该信号量为 0 从而阻塞尝试 acquire() 的接收者,直至提醒者通过调用 release(n) “发信”。在此方面可把信号量当作** 条件变量的替代品** ,** 通常它有更好的性能** 。
1179
1179
1180
+ 假设我们有一个 Web 服务器,它只能处理有限数量的并发请求。为了防止服务器过载,我们可以** 使用信号量来限制并发请求的数量** 。
1181
+
1182
+ ``` cpp
1183
+ // 定义一个信号量,最大并发数为 3
1184
+ std::counting_semaphore<3 > semaphore{ 3 };
1185
+
1186
+ void handle_request(int request_id) {
1187
+ // 请求到达,尝试获取信号量
1188
+ std::cout << "进入 handle_request 尝试获取信号量\n";
1189
+
1190
+ semaphore.acquire();
1191
+
1192
+ std::cout << "成功获取信号量\n";
1193
+
1194
+ // 此处延时三秒可以方便测试,会看到先输出 3 个“成功获取信号量”,因为只有三个线程能成功调用 acquire,剩余的会被阻塞
1195
+ std::this_thread::sleep_for (3s);
1196
+
1197
+ // 模拟处理时间
1198
+ std::random_device rd;
1199
+ std::mt19937 gen{ rd() };
1200
+ std::uniform_int_distribution<> dis(1, 5);
1201
+ int processing_time = dis(gen);
1202
+ std::this_thread::sleep_for (std::chrono::seconds (processing_time));
1203
+
1204
+ std::cout << std::format("请求 {} 已被处理\n", request_id);
1205
+
1206
+ semaphore.release();
1207
+ }
1208
+
1209
+ int main () {
1210
+ // 模拟 10 个并发请求
1211
+ std::vector<std::jthread> threads;
1212
+ for (int i = 0; i < 10; ++i) {
1213
+ threads.emplace_back(handle_request, i);
1214
+ }
1215
+ }
1216
+ ```
1217
+
1218
+ > [ 运行] ( https://godbolt.org/z/xs9asvqre ) 测试。
1219
+
1220
+ 这段代码很简单,以至于我们可以在这里来再说一条概念:
1221
+
1222
+ - ` counting_semaphore ` 是一个轻量同步原语,能控制对共享资源的访问。不同于 [ std::mutex] ( https://zh.cppreference.com/w/cpp/thread/mutex ) ,` counting_semaphore ` ** 允许同一资源进行多个并发的访问** ,至少允许 ` LeastMaxValue ` 个同时的访问者。
1223
+ - ` binary_semaphore ` 是 ` std::counting_semaphore ` 的特化的别名,其 ` LeastMaxValue ` 为 1。
1224
+
1225
+ ` LeastMaxValue ` 是我们设置的非类型模板参数,意思是信号量维护的计数最大值。我们这段代码设置的是 ` 3 ` ,也就是允许 3 个同时访问者。事实上我们的代码就是这样做的。
1226
+
1227
+ 牢记信号量的基本的概念不变,计数的值不能小于 ` 0 ` ,如果当前信号量的计数值为 ` 0 ` ,那么执行“*** 等待*** ”(acquire)操作的线程将会** 一直阻塞** 。明白这点,那么就都不存在问题。
1228
+
1229
+ 通过这种方式,可以有效控制 Web 服务器处理并发请求的数量,防止服务器过载。
1230
+
1180
1231
[ ^ 4 ] :注:** 如果信号量只有二进制的 0 或 1,称为二进制信号量(binary semaphore)** ,这就是这个类型名字的由来。
1181
1232
1182
1233
## 总结
0 commit comments