1. 程式人生 > >C++11之lock_guard學習總結和程式碼例項

C++11之lock_guard學習總結和程式碼例項

std::lock_gurad 是 C++11 中定義的模板類。定義如下:

template<class _Mutex>
    class lock_guard
    {   // class with destructor that unlocks mutex
public:
    typedef _Mutex mutex_type;

    explicit lock_guard(_Mutex& _Mtx)
        : _MyMutex(_Mtx)
        {   // construct and lock
        _MyMutex.lock();
        }

    lock_guard(_Mutex& _Mtx, adopt_lock_t)
        : _MyMutex(_Mtx)
        {   // construct but don't lock
} ~lock_guard() _NOEXCEPT { // unlock _MyMutex.unlock(); } lock_guard(const lock_guard&) = delete; lock_guard& operator=(const lock_guard&) = delete; private: _Mutex& _MyMutex; };

在 lock_guard 物件構造時,傳入的 Mutex 物件(即它所管理的 Mutex 物件)會被當前執行緒鎖住。在lock_guard 物件被析構時,它所管理的 Mutex 物件會自動解鎖,由於不需要程式設計師手動呼叫 lock 和 unlock 對 Mutex 進行上鎖和解鎖操作,因此這也是最簡單安全的上鎖和解鎖方式,尤其是在程式丟擲異常後先前已被上鎖的 Mutex 物件可以正確進行解鎖操作,極大地簡化了程式設計師編寫與 Mutex 相關的異常處理程式碼。

程式碼中
lock_guard(const lock_guard&) = delete;
lock_guard& operator=(const lock_guard&) = delete;
禁用了拷貝建構函式和賦值建構函式.保證了 lock_guard 物件的所有權不會被轉移.

程式碼例項1:使用固定順序獲取鎖

#include <mutex>  
#include<unistd.h>  
#include<thread>  
#include<iostream>  
using namespace std
; class big_object { public: big_object(int i=0):data(i){} public: int data; }; void swap(big_object& lhs,big_object& rhs) { sleep(1); cout<<"swap()"<<endl; } class X { private: big_object some_detail; mutable std::mutex m; public: X(big_object const& sd):some_detail(sd){} friend void swap(X& lhs, X& rhs) { if(&lhs==&rhs) return; std::lock(lhs.m,rhs.m);//C++庫會自動生成加鎖順序,即使呼叫順序不一致 std::lock_guard<std::mutex> lock_a(lhs.m,std::adopt_lock);//adopt_lock是告訴lock_guard物件mutex已經被上鎖,而lock_gurad物件將獲得mutex的所有權,這樣就可以保證在lock可能出現異常導致沒有unlock的情形不會出現,棧物件會在異常丟擲後自動析構 std::lock_guard<std::mutex> lock_b(rhs.m,std::adopt_lock); swap(lhs.some_detail,rhs.some_detail); } }; void threadFun(X& one,X& two){ swap(one,two); } int main() { big_object ten(10),hundred(100); X one(ten),two(hundred); thread threadOne(threadFun,ref(one),ref(two));//不同執行緒有不同的引數呼叫順序,ref表示傳遞的是引用,否則只有執行緒函式中傳引用無效 thread threadTwo(threadFun,ref(two),ref(one)); threadOne.join(); threadTwo.join(); return 0; }

程式碼例項2:層次鎖
lock hierarchy指的是給每個mutex分配一個標號從而對mutex邏輯排序。限制條件是:當執行緒已經持有編號比n小的鎖時不能再請求標號為n的mutex.

#include <mutex>  
#include <stdexcept>  
class hierarchical_mutex//可用於lock_guard<hierarchical_mutex>  
{  
    std::mutex internal_mutex;//  
    unsigned long const hierarchy_value;//mutex所在的層次  
    unsigned long previous_hierarchy_value;//記錄前一個mutex的層次,用於解鎖時恢復執行緒的層次  
    static thread_local unsigned long this_thread_hierarchy_value;//執行緒所在的層次,是個執行緒私有資料  

    void check_for_hierarchy_violation()//檢查當前mutex是否小於執行緒層次,不是則丟擲異常  
    {  
        if(this_thread_hierarchy_value <= hierarchy_value)  
        {  
            throw std::logic_error("mutex hierarchy violated");  
        }  
    }  
    void update_hierarchy_value()//更新執行緒的層次  
    {  
        previous_hierarchy_value=this_thread_hierarchy_value;//通過previous_hierarchy_value記住執行緒的層次  
        this_thread_hierarchy_value=hierarchy_value;//用當前mutex的層次更新執行緒層次  
    }  
public:  
    explicit hierarchical_mutex(unsigned long value):  
        hierarchy_value(value),//mutex層次初始值  
        previous_hierarchy_value(0)  
    {}  
    void lock()//對mutex加鎖  
    {  
        check_for_hierarchy_violation();//先檢查,保證mutex層次小於執行緒層次  
        internal_mutex.lock();  
        update_hierarchy_value();//更新執行緒層次  
    }  
    void unlock()//對mutex解鎖  
    {  
        this_thread_hierarchy_value=previous_hierarchy_value;//用記錄的previous_hierarchy_value恢復執行緒層次  
        internal_mutex.unlock();  
    }  
    bool try_lock()//嘗試加鎖,若mutex已被其它上鎖則返回false  
    {  
        check_for_hierarchy_violation();  
        if(!internal_mutex.try_lock())  
            return false;  
        update_hierarchy_value();  
        return true;  
    }  
};  
thread_local unsigned long  
    hierarchical_mutex::this_thread_hierarchy_value(ULONG_MAX);//執行緒層次初始值為最大,保證開始可以對任意mutex上鎖