C++11之lock_guard學習總結和程式碼例項
阿新 • • 發佈:2019-02-11
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上鎖