使测试避免依赖实时

问题描述 投票:0回答:1

我的队列中有两个函数:

    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();
    }

现在我有这样一个测试(GoogleTest):

    std::thread t{[this] {
        EXPECT_EQ(queue.waitAndPeek(), 66);
    }};
    std::this_thread::sleep_for(3000ms);
    queue.push(66);
    t.join();

您知道如何使该测试不依赖于实时吗?我不想等 2000 毫秒。

c++ multithreading queue thread-safety
1个回答
0
投票

所以你想测试 wait() 阻塞后调用 Push() 的情况。

一种方法是引入一个侧通道让测试知道 wait() 已经开始:

bool is_waiting() {
    std::unique_lock<std::mutex> lock(mutex);
    return is_waiting_;
}

T waitAndPeek() {
    std::unique_lock<std::mutex> lock(mutex);
    is_waiting_ = true;
    conditionVariable.wait(lock, [&] {
        return !queue.empty();
    });
    is_waiting_ = false;
    return queue.front();
}

然后用繁忙的循环代替睡眠:

while (!queue.is_waiting()) {}

保持睡眠但减少问题的另一种方法是反转执行线程,以便主测试线程在辅助线程推送时调用 waitAndPeek():

std::thread t{[this] {
    std::this_thread::sleep_for(10ms);
    queue.push(66);
}};
EXPECT_EQ(queue.waitAndPeek(), 66);
t.join();

这比第一种方法侵入性小,但仍然可能需要小睡一会儿。与第一种情况相比,睡眠时间可以减少,因为这里我们先尽快进入 wait(),然后等待推送,而在原始测试中需要更多时间才能调用 wait():线程需要生成,发生上下文切换,然后才进入 wait()。

请注意,可能需要某种形式的睡眠,例如睡觉。如果您在单核繁忙 CI 实例上运行,那么对于繁忙循环,您还可以考虑添加一个微小的睡眠或 thread_yield() 调用。

© www.soinside.com 2019 - 2024. All rights reserved.