2014-03-04 64 views
4

我正在尋找一些錯誤,我們有一些凌亂的線程/條件變量類被更新爲使用C++ 11線程。在追捕過程中,我遇到的GCC代碼庫執行以下操作:GCC C++ 11條件變量等待內部

template<typename _Lock> 
    void 
    wait(_Lock& __lock) 
    { 
    unique_lock<mutex> __my_lock(_M_mutex); 
    _Unlock<_Lock> __unlock(__lock); 
    // _M_mutex must be unlocked before re-locking __lock so move 
    // ownership of _M_mutex lock to an object with shorter lifetime. 
    unique_lock<mutex> __my_lock2(std::move(__my_lock)); 
    _M_cond.wait(__my_lock2); 
    } 

儘管評論,我難以理解的舉動構造的目的,在這裏__my_lock2。爲什麼__my_lock在這裏移動到__my_lock2?

+2

我懷疑它與'__my_lock'析構函數在**'__unlock'之後被調用**有關,而'__my_lock2'將首先被銷燬。它基本上是圍繞FILO生命週期規則進行黑客攻擊。 – pmdj

回答

10

這看起來不像condition_variable的代碼。它看起來像condition_variable_any的代碼。後者具有模板等待功能。前者不。

N2406可能會說明您所看到的內容。在N2406中,condition_variable_any改爲gen_cond_var,但其他情況下,類型相同。本文描述了一種死鎖情況,在這種情況下,除非非常小心地確保_M_mutex__lock以非常特定的順序鎖定和解鎖,否則會導致死鎖。

雖然您展示的代碼和N2406的代碼不一樣,但我強烈懷疑它們都是按照順序鎖定和解鎖這兩個鎖,以避免N2406中描述的死鎖。如果沒有進一步瞭解_Unlock的定義,我不能絕對確定。然而一個強有力的線索是在這個等待函數的N2406中的最終評論:

} // mut_.unlock(), external.lock() 

即,在鎖定外部__lock之前,必須解鎖成員互斥鎖。通過移動__my_lock與範圍小於的__unlock一個局部變量,它是很有可能的

} // _M_mutex.unlock(), __lock.lock() 

正確的順序已經實現。爲了理解爲什麼這個順序非常重要,你必須閱讀N2406的相關部分(它可以防止死鎖)。

1

它看起來像重新排列對__lock__my_lock變量的銷燬。

的呼聲應該是這樣的:

construct __my_lock // locks _M_mutex 
construct __unlock // unlocks __lock 
construct __my_lock2 // Does nothing as its a move. 

_M_cond.wait(__my_lock2); 

destroy __mylock2 // unlocks __M_mutex 
destroy __unlock // locks __lock again 
destroy __mylock // does nothing as its been moved 

不具備轉移的順序將是

construct __my_lock // locks _M_mutex 
construct __unlock // unlocks __lock 

_M_cond.wait(__my_lock); 

destroy __unlock // locks __lock 
destroy __mylock // unlocks _M_mutex 

這可能會導致死鎖在對方的回答

3

功能提到(我認爲這是std::condition_variable_any<_Lock>::wait)通過建立一個鎖定順序不變量來避免死鎖,因爲__lock必須被鎖定e獲取_M_mutex。雖然這樣做,它仍然必須保證在等待內部條件變量_M_cond時不會保持__lock。請注意0​​是RAII 解鎖對象。它通過在其構造函數中解鎖,並在解析器中鎖定執行與通常鎖守相反的功能。事件的必要的排序是:

  1. 獲取__lock(該wait通話的前置條件)
  2. 獲取_M_mutex(在__my_lock構造函數)
  3. 釋放__lock(在__unlock構造函數)
  4. 原子發佈_M_mutex並等待_M_cond(發生在_M_cond.wait
  5. 重新獲取_M_mutex關於wa Keup酒店(也_M_cond.wait
  6. 釋放_M_mutex(在__my_lock2析構函數)
  7. 重新獲得__lock(在__unlock析構函數)

__my_lock__my_lock2此舉是必要的,這樣__my_lock2__unlock之前被銷燬確保事件6發生在7之前而不是之後。