如何让队列的GoogleTest测试摆脱实时依赖?移除sleep_for等待
如何修改依赖实时等待的GoogleTest测试用例?
现有队列实现代码
void push(const T& object) { std::lock_guard<std::mutex> lock(mutex); queue.emplace(object); conditionVariable.notify_all(); } T waitAndPeek() { std::unique_lock<std::mutex> lock(mutex); conditionVariable.wait(lock, [&] { return !queue.empty(); }); return queue.front(); }
当前测试代码的问题
原测试通过std::this_thread::sleep_for(3000ms)等待子线程进入waitAndPeek的阻塞状态,这种方式既低效又不可靠——不同环境下线程启动速度差异大,可能出现等待时间不足导致测试失败,或等待过长浪费时间。
std::thread t{[this] { EXPECT_EQ(queue.waitAndPeek(), 66); }}; std::this_thread::sleep_for(3000ms); queue.push(66); t.join();
修改后的无等待测试方案
可以用std::promise + std::future实现线程间的同步,确保子线程启动后再执行push操作,完全不需要依赖实时等待:
// 创建同步用的promise和future std::promise<void> thread_ready; std::future<void> future = thread_ready.get_future(); std::thread t{[this, &thread_ready] { // 标记子线程已启动,即将进入waitAndPeek thread_ready.set_value(); EXPECT_EQ(queue.waitAndPeek(), 66); }}; // 等待子线程发出启动完成的信号 future.get(); // 此时子线程已准备好,执行push唤醒等待 queue.push(66); t.join();
方案说明
std::promise和std::future用于主线程和子线程的同步:子线程启动后立即通过thread_ready.set_value()通知主线程,主线程通过future.get()阻塞等待这个信号。- 主线程收到信号后执行
push,此时无论子线程是否已经进入conditionVariable.wait的阻塞状态,测试都能正确执行:- 若子线程已进入阻塞,会被
notify_all()唤醒,返回队列头部的66; - 若子线程还未进入阻塞,
push已将元素放入队列,waitAndPeek中的条件会立即满足,直接返回66。
- 若子线程已进入阻塞,会被
C++20及以上的替代方案
如果项目支持C++20,可以用std::latch实现更简洁的同步:
// 初始化一个计数为2的latch,需要两个线程到达同步点才会继续 std::latch sync_latch(2); std::thread t{[this, &sync_latch] { sync_latch.count_down(); // 子线程到达同步点 EXPECT_EQ(queue.waitAndPeek(), 66); }}; sync_latch.count_down(); // 主线程到达同步点 sync_latch.wait(); // 等待两个线程都到达同步点 queue.push(66); t.join();
内容的提问来源于stack exchange,提问作者Dewek
相关产品推荐
相关产品推荐

