c++ - 我如何对 condition_variable::wait 周围的包装器进行单元测试?

标签 c++ multithreading c++11 c++17

我有一个类有一个等待队列被填满的 wait 函数。一旦队列非空,condition_variable 就会收到通知,等待函数会清空队列并处理其中的元素。

我想在单元测试中验证此 wrapper::wait 调用(检查队列是否为非空)实际上阻塞了线程。我有一个不稳定的设置,其中包含一个 atomic_bool,它是在 wait 调用之后设置的,我天真地认为执行以下序列会起作用。

  1. 使用调用wait 的函数创建线程,然后设置atomic_bool
  2. 创建线程后,验证atomic_bool有开始值
  3. 在主线程中将某些内容插入队列,使 atomic_bool 更改其他线程的值。
  4. 在主线程中验证更改的值。

缺少两个同步点:两个“验证”不能保证在我希望它们发生时发生:

  • 我无法验证是否已在线程中调用了 wait。
  • 我无法验证线程是否有机会更改 atomic_bool

有没有什么办法可以在不增加一个或多个额外的condition_variables/mutexes来同步操作的情况下解决这个问题?

最佳答案

这真的是使用 std::condition_variable 的完美场景, 但无论如何:您可以将多个同步点与 std::atomic<int> gate 一起使用.各种值将对测试的不同阶段进行编码。等待值更改的时间超过某个恒定时间 T 将被视为测试用例失败1

  • gate == 0 : 辅助线程未初始化。
  • gate == 1 : 辅助线程已初始化,但尚未响应。
  • gate == 2 : 辅助线程已初始化并正在运行,可以假设已调用 wait .
  • gate == 3 : 主线程已向队列添加内容,辅助线程可能仍在等待。
  • gate == 4 : 辅助线程已退出 wait并设置最后一个值。

如果愿意,您可以省略几个同步点。

主线程

  1. 设置gate到 0。
  2. 生成辅助线程。
  3. 设置gate到 1。
  4. 等待 T gate变成2;失败时:“辅助线程从未达到 wait
  5. 向队列添加一些东西,设置gate到 3.
  6. 等待 T gate变成4;失败时:“辅助线程从未退出 wait
  7. 等待 T 次线程加入;失败时:“辅助线程在退出前挂起”

辅助线程

  1. 等待 T gate变成 1;失败时“主线程在产生后挂起”
  2. 设置gate到 2. 调用 wait .
  3. (调用 wait 退出;队列已处理)。
  4. 等待 T gate变成3;失败时“回到过去”
  5. 设置gate到 4 并退出。

要实现“等待和检查”部分,您可以使用 compare_exchange std::chrono .一个可能的实现可能是这样的:

#include <atomic>
#include <chrono>
#include <condition_variable>

std::cv_status wait_till_reaches(
    std::atomic<int> &gate,
    std::chrono::high_resolution_clock::duration const &rel_time,
    const int desired_value,
    bool increment = false
) {
    const int next_value = desired_value + (increment ? 1 : 0);
    int dummy = desired_value;
    const std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
    while (not gate.compare_exchange_weak(dummy, next_value)) {
        dummy = desired_value;
        if ((std::chrono::high_resolution_clock::now() - start) >= rel_time) {
            return std::cv_status::timeout;
        }
    }
    return std::cv_status::no_timeout;
}

1 这不是测试准确您的代码是否工作,而是测试它是否工作足够快,但另一方面,如果您有一些线程问题,也不能保证测试用例会捕获它(在某些时候,您必须决定等待响应的时间)。

关于c++ - 我如何对 condition_variable::wait 周围的包装器进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41131112/

相关文章:

c++ - 具有函数指针的模板类不接受特化

c++ - 在 C/C++ 良好实践中使用 '!!' 是否常见?

c# - 如何将可选指针参数从 C++ 代码转换为 C#

c++ - 如何在 Linux 上以编程方式 (C/C++) 获取国家/地区代码?

java - 诊断 Java 中断标志

c++ - 指向类成员的指针作为模板参数

c++ - 如何转发 std::initializer_list<T>?

c++ - boost::variant 访问者返回错误(最烦人的解析?)

c++ - 销毁锁定的互斥锁时 pthread_mutex_destroy 的正确行为是什么

java - 我的多线程 "fizz buzz"实现线程安全吗?