2015-02-06 33 views
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; 
}; 

我有兩個想法,現在:

  1. 主要有出於某種原因已經退出。這是一個PoC,所以當出現錯誤時,我們登錄到stdout並調用exit()(是的,我知道,不是最好的,這是從另一個用C++編寫的C風格程序改編的)。我沒有看到任何記錄到終端的東西,但我想有可能輸出被緩衝並且還沒有寫出來?
  2. 調試器以某種方式對我說謊。通常,當它執行此操作時,會將[frames below may be missing/incorrect]放入堆棧跟蹤中,但也可能在沒有這種情況下發生。
+1

您應該通知互斥鎖裏面,或者你可能會遇到種族: 1.'_cv.wait()'計算謂詞,它返回'FALSE' 2'notify_all'被稱爲 3.等待' (鎖)'在'_cv.wait()中調用' 不知道這是不是問題 – StenSoft 2015-02-06 20:20:06

+0

我在cppreference.com上查看std :: condition_variable的文檔,它似乎說你沒有在通知的時候不需要保持鎖定,事實上這樣做是一種性能悲觀化(這是有道理的,因爲任何由於通知而喚醒的線程會立即嘗試搶佔鎖並失敗) – Bwmat 2015-02-06 20:21:55

+0

「通知線程不需要鎖定與t所持有的鎖相同的互斥鎖他在等待線程;實際上這樣做是悲觀化的,因爲通知的線程會立即再次阻塞,等待通知線程釋放鎖定。但是,某些實現(特別是pthread的許多實現)可以識別這種情況,並通過將等待線程從條件變量的隊列直接傳遞到notify通知中的互斥隊列而避免這種「快速等待」情形,而不會喚醒它向上。 「是他們說的。 – Bwmat 2015-02-06 20:23:16

回答

0

事實證明,我無法替換隊列中的項目,導致我的線程在從隊列中檢索時出現死鎖,這意味着調試器對我說謊。 :(