我有一個多線程應用程序(使用std :: thread)和一個管理器(類樹),它在不同的子樹上執行某段代碼(嵌入式結構子樹)在平行下。基本思想是每個SubTree實例都有一個存儲對象的雙端隊列。如果雙端隊列爲空,則線程將等待,直到在雙端隊列中插入新元素或達到終止條件。一個子樹可以生成對象並將它們推送到另一個子樹的雙端隊列中。爲了方便起見,我所有的std :: mutex,std :: locks和std :: variable_condition都存儲在一個名爲「locks」的結構中。C++在調用std :: unique_lock之前解鎖std :: mutex等待
類樹創建運行下面的方法(第一次嘗試)某些線程:
void Tree::launch(SubTree & st, Locks & locks)
{
/* some code */
std::lock_guard<std::mutex> deque_lock(locks.deque_mutex_[st.id_]) ; // lock the access to the deque of subtree st
if (st.deque_.empty()) // check that the deque is still empty
{
// some threads are still running, wait for them to terminate
std::unique_lock<std::mutex> wait_lock(locks.restart_mutex_[st.id_]) ;
locks.restart_condition_[st.id_].wait(wait_lock) ;
}
/* some code */
}
的問題是,當線程正在等待「deque_lock」仍處於鎖定狀態。因此,沒有對象可以被併發的對象添加到當前線程的雙端隊列中。
所以我把lock_guard成unique_lock和管理的手動鎖定/解鎖:
void launch(SubTree & st, Locks & locks)
{
/* some code */
std::unique_lock<std::mutex> deque_lock(locks.deque_mutex_[st.id_]) ; // lock the access to the deque of subtree st
if (st.deque_.empty()) // check that the deque is still empty
{
deque_lock.unlock() ; // unlock the access to the deque to enable the other threads to add objects
// DATA RACE : nothing must happen to the unprotected deque here !!!!!!
// some threads are still running, wait for them to terminate
std::unique_lock<std::mutex> wait_lock(locks.restart_mutex_[st.id_]) ;
locks.restart_condition_[st.id_].wait(wait_lock) ;
}
/* some code */
}
現在的問題,是有數據的比賽,我想,以確保「等待「指令直接在」deque_lock.unlock()「之後執行。有誰會知道用標準庫創建這樣一個關鍵指令序列的方法嗎?
在此先感謝。
感謝您的快速回答和建議,我會在我的代碼中考慮到這一點。但是,在「deque_lock.unlock();」之後沒有保證沒有併發線程不會在雙端隊列中添加對象。然後當前線程將等待,而該deque不是空的。因此,我認爲這裏仍然存在數據競賽。 –
這取決於你想要在隊列中擁有什麼狀態。條件變量經常用於等待,而隊列不是空的,有兩個元素不會打擾你。作爲事後的想法,我想知道,爲什麼不用一個互斥體排除對隊列和鎖定條件變量的訪問,即只使用'locks.deque_mutex_ [st.id]'。這將完全排除你的數據競爭(如果這是一個合理的解決方案,我不能說這些代碼部分)。 –