如何测试我的阻塞队列实际阻塞

时间:2017-11-17 15:29:06

标签: c++ multithreading unit-testing c++11 blocking

我有一个阻塞队列(我真的很难改变它的实现),我想测试它实际阻塞。特别是,pop方法必须在队列为空时阻止,并在执行push后立即取消阻止。请参阅以下用于测试的伪C ++ 11代码:

BlockingQueue queue; // empty queue

thread pushThread([] 
{ 
    sleep(large_delay);
    queue.push(); 
});

queue.pop();

显然它并不完美,因为可能会发生整个线程pushThread被执行并在调用pop之前终止,即使延迟很大,延迟越大我越多必须等待测试结束。

如何正确确保pop在调用push之前执行,并且在push返回之前是阻塞?

3 个答案:

答案 0 :(得分:1)

如果不向BlockingQueue添加一些额外的状态和接口,我不相信这是可能的。

证明就是这样的。您希望等到pop上的阅读主题被阻止。但是没有办法区分它和即将执行pop的线程。无论你在调用pop之前或之后放置什么,这都是正确的。

如果你真的想以100%的可靠性修复它,你需要在队列中添加一些状态,由队列的互斥锁保护,这意味着“有人在等待”。然后,pop调用必须在它原子地释放互斥锁之前更新该状态,并在内部条件变量上进入休眠状态。 push线程可以获取互斥锁并等到“某人正在等待”。为避免繁忙循环,您需要再次使用条件变量。

所有这些机器几乎和队列本身一样复杂,所以也许你也想测试它......这种多线程代码就像“代码覆盖”这样的概念 - 甚至可以称为单元测试本身 - 分解一下。有太多可能的交错操作。

在实践中,我可能会采用你最初的睡眠方法。

答案 1 :(得分:1)

template<class T>
struct async_queue {
  T pop() {
    auto l = lock();
    ++wait_count;
    cv.wait( l, [&]{ return !data.empty(); } );
    --wait_count;
    auto r = std::move(data.front());
    data.pop_front();
    return r;
  }
  void push(T in) {
    {
      auto l = lock();
      data.push_back( std::move(in) );
    }
    cv.notify_one();
  }
  void push_many(std::initializer_list<T> in) {
    {
      auto l = lock();
      for (auto&& x: in) 
        data.push_back( x );
    }
    cv.notify_all();
  }
  std::size_t readers_waiting() {
    return wait_count;
  }
  std::size_t data_waiting() const {
    auto l = lock();
    return data.size();
  }
private:
  std::queue<T> data;
  std::condition_variable cv;
  mutable std::mutex m;
  std::atomic<std::size_t> wait_count{0};
  auto lock() const { return std::unique_lock<std::mutex>(m); }

};

或某些。

在推送线程中,忙于等待readers_waiting,直到它通过1.

此时您已锁定并且在锁定解锁之前处于cv.wait范围内。做一个push

理论上,一个无限慢的读者线程可能已经进入cv.wait并且仍然在你调用push时评估第一个lambda,但是一个无限慢的读者线程与被阻塞的线程没有什么不同...

然而,这确实涉及慢线程启动等。

readers_waitingdata_waiting用于除调试以外的任何其他操作通常都是代码味道。

答案 2 :(得分:0)

您可以使用std::condition_variable来完成此操作。 cppreference.com的帮助页面实际上显示了一个非常好的cosumer-producer示例,它应该是您正在寻找的内容:http://en.cppreference.com/w/cpp/thread/condition_variable

编辑:实际上,德语版的cppreference.com有一个更好的例子:-) http://de.cppreference.com/w/cpp/thread/condition_variable