互斥鎖保證了線程間的同步,可是卻將並行操做變成了串行操做,這對性能有很大的影響,因此咱們要儘量的減少鎖定的區域,也就是使用細粒度鎖。編程
這一點lock_guard
作的很差,不夠靈活,lock_guard
只能保證在析構的時候執行解鎖操做,lock_guard
自己並無提供加鎖和解鎖的接口,可是有些時候會有這種需求。看下面的例子。併發
class LogFile { std::mutex _mu; ofstream f; public: LogFile() { f.open("log.txt"); } ~LogFile() { f.close(); } void shared_print(string msg, int id) { { std::lock_guard<std::mutex> guard(_mu); //do something 1 } //do something 2 { std::lock_guard<std::mutex> guard(_mu); // do something 3 f << msg << id << endl; cout << msg << id << endl; } } };
上面的代碼中,一個函數內部有兩段代碼須要進行保護,這個時候使用lock_guard
就須要建立兩個局部對象來管理同一個互斥鎖(其實也能夠只建立一個,可是鎖的力度太大,效率不行),修改方法是使用unique_lock
。它提供了lock()
和unlock()
接口,能記錄如今處於上鎖仍是沒上鎖狀態,在析構的時候,會根據當前狀態來決定是否要進行解鎖(lock_guard
就必定會解鎖)。上面的代碼修改以下:函數
class LogFile { std::mutex _mu; ofstream f; public: LogFile() { f.open("log.txt"); } ~LogFile() { f.close(); } void shared_print(string msg, int id) { std::unique_lock<std::mutex> guard(_mu); //do something 1 guard.unlock(); //臨時解鎖 //do something 2 guard.lock(); //繼續上鎖 // do something 3 f << msg << id << endl; cout << msg << id << endl; // 結束時析構guard會臨時解鎖 // 這句話可要可不要,不寫,析構的時候也會自動執行 // guard.ulock(); } };
上面的代碼能夠看到,在無需加鎖的操做時,能夠先臨時釋放鎖,而後須要繼續保護的時候,能夠繼續上鎖,這樣就無需重複的實例化lock_guard
對象,還能減小鎖的區域。一樣,可使用std::defer_lock
設置初始化的時候不進行默認的上鎖操做:性能
void shared_print(string msg, int id) { std::unique_lock<std::mutex> guard(_mu, std::defer_lock); //do something 1 guard.lock(); // do something protected guard.unlock(); //臨時解鎖 //do something 2 guard.lock(); //繼續上鎖 // do something 3 f << msg << id << endl; cout << msg << id << endl; // 結束時析構guard會臨時解鎖 }
這樣使用起來就比lock_guard
更加靈活!而後這也是有代價的,由於它內部須要維護鎖的狀態,因此效率要比lock_guard
低一點,在lock_guard
能解決問題的時候,就是用lock_guard
,反之,使用unique_lock
。學習
後面在學習條件變量的時候,還會有unique_lock
的用武之地。線程
另外,請注意,unique_lock
和lock_guard
都不能複製,lock_guard
不能移動,可是unique_lock
能夠!code
// unique_lock 能夠移動,不能複製 std::unique_lock<std::mutex> guard1(_mu); std::unique_lock<std::mutex> guard2 = guard1; // error std::unique_lock<std::mutex> guard2 = std::move(guard1); // ok // lock_guard 不能移動,不能複製 std::lock_guard<std::mutex> guard1(_mu); std::lock_guard<std::mutex> guard2 = guard1; // error std::lock_guard<std::mutex> guard2 = std::move(guard1); // error