2016-07-18 69 views
3

我想知道當您移動包含recursive_mutexunique_lock時會發生什麼。將unique_lock <recursive_mutex>移動到另一個線程

具體來說,我一直在尋找這樣的代碼:

recursive_mutex g_mutex; 

#define TRACE(msg) trace(__FUNCTION__, msg) 

void trace(const char* function, const char* message) 
{ 
    cout << std::this_thread::get_id() << "\t" << function << "\t" << message << endl; 
} 

future<void> foo() 
{ 
    unique_lock<recursive_mutex> lock(g_mutex); 
    TRACE("Owns lock"); 
    auto f = std::async(launch::async, [lock = move(lock)]{ 
     TRACE("Entry"); 
     TRACE(lock.owns_lock()? "Owns lock!" : "Doesn't own lock!"); // Prints Owns lock! 
     this_thread::sleep_for(chrono::seconds(3)); 
    }); 
    TRACE(lock.owns_lock()? "Owns lock!" : "Doesn't own lock!"); // Prints Doesn't own lock! 
    return f; 
} 


int main() 
{ 
    unique_lock<recursive_mutex> lock(g_mutex); 
    TRACE("Owns lock"); 
    auto f = foo();  
    TRACE(lock.owns_lock()? "Owns lock!" : "Doesn't own lock!");  // Prints Owns lock! 
    f.wait(); 
    TRACE(lock.owns_lock()? "Owns lock!" : "Doesn't own lock!");  // Prints Owns lock! 
} 

此示例代碼的輸出讓我吃驚不少。 main()中的unique_lock如何知道線程釋放了互斥鎖?這是真的嗎?

+3

目前尚不清楚你會發現令人驚訝的事情。 'unique_lock'中有一個簡單的布爾成員,它的'owns_lock()'返回,並且通過移動構造函數以可預測和記錄的方式移動。 'owns_lock()'不會觸及底層互斥體。話雖如此,你的程序展現出未定義的行爲:當工作線程上'unique_lock'被銷燬時,它調用'g_mutex.unlock()',但工作線程不會在'g_mutex'(這是一個pre - unlock()''的必要條件)。 –

+0

@IgorTandetnik謝謝。所以不可能在線程之間移動'recursive_mutex'的所有權?如果互斥量不是遞歸會怎麼樣?將unique_lock移動到所有者線程是否真的會移動? –

+3

在線程之間移動'unique_lock'確實對你沒有任何好處。意識到'unique_lock'只不過是一個'互斥體*'指針和一個'bool擁有'標誌 - 沒有黑魔法。移動構造器簡單地移動該指針和布爾值。在不同於調用'my_mutex.lock()'的線程上調用'my_mutex.unlock()'會展示未定義的行爲,無論是通過欺騙'unique_lock'來明確或間接完成。所有互斥口味都是如此。 –

回答

3

您似乎將某些魔法屬性歸於unique_lock。它沒有,這是一個非常簡單的課程。它有兩個數據成員,Mutex* pmbool owns(僅顯示會員名稱)。 lock()簡單地爲pm->lock(); owns = true;unlockpm->unlock(); owns = false;。破壞者是if (owns) unlock();。將構造函數副本移動到兩個成員上,並相應地將它們的原始位置設置爲nullptrfalseowns_lock()返回值爲owns的成員。

所有的線程同步魔法都在互斥量本身,以及它的lock()unlock()方法。 unique_lock僅僅是一個薄薄的包裝紙。

現在,作爲先決條件,調用mutex.unlock()的線程必須持有該互斥鎖(意味着該線程先前已在其上調用lock()),否則該程序會顯示未定義的行爲。無論你明確地致電unlock,還是慫恿像unique_lock這樣的助手爲你調用它,情況都是如此。根據所有這些,將unique_lock實例移動到另一個線程僅僅是此後不久觸發未定義行爲的配方;沒有好處。

相關問題