3
我得到我的C++程序,它使用的std ::線程的std ::互斥的std :: condition_variable死鎖等死鎖沒有用戶代碼
沒有什麼本身奇怪的這件事,直到我看看堆棧每個在我進程中的線程的:
8532 0 Main Thread Main Thread msvcr120.dll!Concurrency::details::ExternalContextBase::Block Normal
[email protected]()
[email protected]()
[email protected]()
msvcr120.dll!Concurrency::details::ExternalContextBase::Block() Line 145
[email protected]()
[email protected]()
[email protected]()
msvcr120.dll!_initterm(void (void) * * pfbegin, void (void) * * pfend) Line 954
-
6484 0 Worker Thread [email protected]() [email protected] Normal
[email protected]()
[email protected]()
[email protected]@12()
[email protected]()
[email protected]()
-
6296 0 Worker Thread msvcr120.dll!_threadstartex msvcr120.dll!Concurrency::details::ExternalContextBase::Block Normal
[email protected]()
[email protected]()
[email protected]()
msvcr120.dll!Concurrency::details::ExternalContextBase::Block() Line 145
msvcp120.dll!std::_Thrd_startX(struct _Thrd_imp_t *,unsigned int (*)(void *),void *)
msvcr120.dll!_callthreadstartex() Line 376
msvcr120.dll!_threadstartex(void * ptd) Line 354
[email protected]@12()
[email protected]()
[email protected]()
沒有一個線程似乎在執行我的代碼,並且我知道我們已經進入了main,因爲程序在掛起之前做了一些事情。
我使用下面的類與我的std ::線程進行通信,如果我做了一些錯誤有:
template <typename T>
class BlockingQueue
{
public:
BlockingQueue() : _active(true) {}
bool Get(T& out)
{
std::unique_lock<std::mutex> lock(_mutex);
_cv.wait(lock, [&](){ return !_queue.empty() || !_active; });
if (_queue.empty())
{
assert(!_active);
return false;
}
out = std::move(_queue.front());
_queue.pop();
return true;
}
void Put(const T& in)
{
{
std::unique_lock<std::mutex> lock(_mutex);
_queue.push(in);
}
_cv.notify_one();
}
void Put(T&& in)
{
{
std::unique_lock<std::mutex> lock(_mutex);
_queue.push(std::move(in));
}
_cv.notify_one();
}
void Finish()
{
{
std::unique_lock<std::mutex> lock(_mutex);
_active = false;
}
_cv.notify_all();
}
private:
bool _active;
std::mutex _mutex;
std::condition_variable _cv;
std::queue<T> _queue;
};
我有兩個想法,現在:
- 主要有出於某種原因已經退出。這是一個PoC,所以當出現錯誤時,我們登錄到stdout並調用exit()(是的,我知道,不是最好的,這是從另一個用C++編寫的C風格程序改編的)。我沒有看到任何記錄到終端的東西,但我想有可能輸出被緩衝並且還沒有寫出來?
- 調試器以某種方式對我說謊。通常,當它執行此操作時,會將
[frames below may be missing/incorrect]
放入堆棧跟蹤中,但也可能在沒有這種情況下發生。
您應該通知互斥鎖裏面,或者你可能會遇到種族: 1.'_cv.wait()'計算謂詞,它返回'FALSE' 2'notify_all'被稱爲 3.等待' (鎖)'在'_cv.wait()中調用' 不知道這是不是問題 – StenSoft 2015-02-06 20:20:06
我在cppreference.com上查看std :: condition_variable的文檔,它似乎說你沒有在通知的時候不需要保持鎖定,事實上這樣做是一種性能悲觀化(這是有道理的,因爲任何由於通知而喚醒的線程會立即嘗試搶佔鎖並失敗) – Bwmat 2015-02-06 20:21:55
「通知線程不需要鎖定與t所持有的鎖相同的互斥鎖他在等待線程;實際上這樣做是悲觀化的,因爲通知的線程會立即再次阻塞,等待通知線程釋放鎖定。但是,某些實現(特別是pthread的許多實現)可以識別這種情況,並通過將等待線程從條件變量的隊列直接傳遞到notify通知中的互斥隊列而避免這種「快速等待」情形,而不會喚醒它向上。 「是他們說的。 – Bwmat 2015-02-06 20:23:16