[英]How to test my blocking queue actually blocks
我有一個阻塞隊列(我真的很難改變它的實現),我想測試它實際阻塞。 特別是,如果隊列為空,則pop
方法必須阻塞,並且只要執行push
就解除阻塞。 請參閱以下用於測試的偽C ++ 11代碼:
BlockingQueue queue; // empty queue
thread pushThread([]
{
sleep(large_delay);
queue.push();
});
queue.pop();
顯然它並不完美,因為可能會發生整個線程pushThread
被執行並在調用pop
之前終止,即使延遲很大,延遲越大,我就越需要等待測試結束。
如何正確確保在調用push
之前執行pop
,並且直到push
返回為止?
如果不向BlockingQueue添加一些額外的狀態和接口,我不相信這是可能的。
證明就是這樣的。 你想要等到pop
阻止閱讀線程。 但是沒有辦法區分它和即將執行pop
的線程。 無論你在調用pop
之前或之后放置什么,這都是正確的。
如果你真的想以100%的可靠性來修復它,你需要在隊列中添加一些狀態,由隊列的互斥鎖保護,這意味着“有人正在等待”。 然后, pop
調用必須在它原子釋放互斥鎖之前更新該狀態,並在內部條件變量上進入休眠狀態。 push
線程可以獲取互斥鎖並等待“有人在等待”。 要避免繁忙循環,您需要再次使用條件變量。
所有這些機器幾乎和隊列本身一樣復雜,所以也許你也想測試它......這種多線程代碼就像“代碼覆蓋”這樣的概念 - 甚至可以說是單元測試本身 - - 分解一下。 存在太多可能的操作交錯。
在實踐中,我可能會采用你原來的睡眠方法。
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
之前都在cv.wait
之內。 push
。
理論上,一個無限慢的讀者線程可能已經進入cv.wait
並且仍然在你調用push
時評估第一個lambda,但是一個無限慢的讀者線程與一個被阻塞的線程沒有什么不同......
然而,這確實涉及慢線程啟動等。
使用readers_waiting
和data_waiting
進行調試data_waiting
的任何操作通常都是代碼味道。
您可以使用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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.