2016-11-30 125 views
0

我有点卡住了这个问题,所以这是我的呼救声。死锁与提升:: condition_variable

我有一个管理器将某些事件推送到队列中,这是在另一个线程中进行的。 我不希望此线程在队列中的事件“忙于等待”,因为它可能一直为空(以及它可能始终为满)。 另外,我需要m_bShutdownFlag来在需要时停止线程。 所以我想尝试一下condition_variable这种情况:如果有东西被推到队列中,那么线程就开始工作。

简化代码:

class SomeManager { 
public: 
    SomeManager::SomeManager() 
     : m_bShutdownFlag(false) {} 

    void SomeManager::Initialize() { 
     boost::recursive_mutex::scoped_lock lock(m_mtxThread); 
     boost::thread thread(&SomeManager::ThreadProc, this); 
     m_thread.swap(thread); 
    } 

    void SomeManager::Shutdown() { 
     boost::recursive_mutex::scoped_lock lock(m_mtxThread); 
     if (m_thread.get_id() != boost::thread::id()) { 
      boost::lock_guard<boost::mutex> lockEvents(m_mtxEvents); 
      m_bShutdownFlag = true; 
      m_condEvents.notify_one(); 
      m_queue.clear(); 
     } 
    } 

    void SomeManager::QueueEvent(const SomeEvent& event) { 
     boost::lock_guard<boost::mutex> lockEvents(m_mtxEvents); 
     m_queue.push_back(event); 
     m_condEvents.notify_one(); 
    } 

private: 
    void SomeManager::ThreadProc(SomeManager* pMgr) { 
     while (true) { 
      boost::unique_lock<boost::mutex> lockEvents(pMgr->m_mtxEvents); 
      while (!(pMgr->m_bShutdownFlag || pMgr->m_queue.empty())) 
       pMgr->m_condEvents.wait(lockEvents); 

      if (pMgr->m_bShutdownFlag) 
       break; 
      else 
       /* Thread-safe processing of all the events in m_queue */ 
     } 
    } 

    boost::thread m_thread; 
    boost::recursive_mutex m_mtxThread; 
    bool m_bShutdownFlag; 

    boost::mutex m_mtxEvents; 
    boost::condition_variable m_condEvents; 
    SomeThreadSafeQueue m_queue; 
} 

但是,当我有两个(或更多)几乎同时呼叫测试,以QueueEvent,它在该行boost::lock_guard<boost::mutex> lockEvents(m_mtxEvents);被锁定,直到永远。

似乎第一个电话永远不会释放lockEvents,所以其余的只是等待其释放。

请帮我找出我做错了什么,以及如何解决这个问题。

回答

0

有一些事情要对你的代码指出:

  1. 您不妨加入你的线程调用shutdown后,要保证你的主线程不会将您的其他线程之前完成。
  2. m_queue.clear();关机是在您的m_mtxEvents互斥锁之外完成的,这意味着它不像您认为的那样安全。
  3. 您的队列中的'线程安全处理'应该只是关闭一个项目,然后在您关闭以处理事件时释放锁。您没有明确指出,但如果不这样做将导致锁定,从而防止添加项目。

关于像这样的线程阻塞的好消息是,你可以轻松地中断和检查其他线程正在做什么,并找到持有锁的那个。根据我的评论#3,你可能需要很长时间来处理一个事件。另一方面,它可能是你有一个死锁。在任何情况下,你需要的是使用你的调试器来确定你做错了什么,因为你的示例没有足够的证明你的问题。

+0

谢谢,我已修复#1和#2。我的问题的原因是在队列元素的处理中。由于处理过程中的'while'周期不好,有几个元素永远持续处理。 – Ganya

0

在ThreadProc内部,while(ture)循环,lockEvents在任何情况下都不解锁。尝试把锁放在范围内等待。

+0

其实这部分对我来说是最奇怪的。它看起来像我永远不会得到处理队列中的任何事件,但这不是事实。当我在两次调用之间调用两次'QueueEvent'时,一切正常。 – Ganya

+0

无论如何,感谢您的建议,我会尝试 - 至少听起来很理智。 – Ganya