在另一线程独立计时for循环每轮迭代的最优实现方案
跨线程for循环单轮迭代超时检测方案优化
原实现的核心问题
原有代码随机超时是两个底层逻辑错误导致的:
- 客户端锁持有时机错误:客户端在执行耗时的
do work逻辑前就获取了互斥锁,整个任务执行期间都独占CLIENT_MUTEX,服务端的wait_for需要先获取锁才能进入等待状态,锁等待的时间会被计入1秒超时判定,自然会随机触发超时。 - 未处理条件变量虚假唤醒:标准库的条件变量允许无理由的虚假唤醒,直接用
wait_for的返回值判断是否收到通知,会出现假醒误判、漏判的问题。
优化后实现方案
新增一个受互斥锁保护的共享迭代计数器,对齐两端迭代进度,同时用带谓词的wait_for规避虚假唤醒问题。
共享全局变量定义
#include <mutex> #include <condition_variable> #include <chrono> #include <iostream> std::mutex CLIENT_MUTEX; std::condition_variable CLIENT_CV; // 记录客户端已完成的迭代轮次,受CLIENT_MUTEX保护 int g_finished_client_tick = 0;
服务端代码
void server_thread() { int expected_tick = 1; for (int i = 0; i < 10; i++) { std::unique_lock<std::mutex> lock(CLIENT_MUTEX); // 带谓词的等待,自动过滤虚假唤醒,只有客户端完成当前轮次才会返回true bool no_timeout = CLIENT_CV.wait_for(lock, std::chrono::seconds(1), [&]() { return g_finished_client_tick == expected_tick; }); if (!no_timeout) { std::cout << "第 " << i << " 轮迭代超时" << std::endl; // 可在此处添加终止客户端的逻辑 break; } expected_tick++; } }
客户端代码
void client_thread() { for (int i = 0; i < 10; i++) { // *注意:耗时逻辑不要持有互斥锁* // do work 执行耗时任务 // 任务完成后再拿锁更新状态、发通知 std::unique_lock<std::mutex> lock(CLIENT_MUTEX); g_finished_client_tick = i + 1; CLIENT_CV.notify_one(); } }
轻量可选方案
如果不需要严格对齐迭代进度,只需要检测单轮超时,可以用原子时间戳实现,逻辑更简单:
#include <atomic> #include <chrono> #include <thread> // 用steady_clock避免系统时间跳变影响 std::atomic<std::chrono::steady_clock::time_point> g_last_tick_time; // 客户端每轮结束更新时间 g_last_tick_time.store(std::chrono::steady_clock::now(), std::memory_order_release); // 服务端循环检测 while (运行中) { auto now = std::chrono::steady_clock::now(); auto duration = now - g_last_tick_time.load(std::memory_order_acquire); if (duration > std::chrono::seconds(1)) { std::cout << "超时" << std::endl; break; } // 每次检测间隔10ms,降低CPU开销 std::this_thread::sleep_for(std::chrono::milliseconds(10)); }
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

