2016-11-30 126 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