2015-02-06 121 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

事实证明,我无法替换队列中的项目,导致我的线程在从队列中检索时出现死锁,这意味着调试器对我说谎。 :(