You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让队列的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();

方案说明

  1. std::promise和std::future用于主线程和子线程的同步:子线程启动后立即通过thread_ready.set_value()通知主线程,主线程通过future.get()阻塞等待这个信号。
  2. 主线程收到信号后执行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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 23:26:22