C++11std::unique_lock與std::lock_guard的區別及多線程應用實例編程
C++多線程編程中一般會對共享的數據進行寫保護,以防止多線程在對共享數據成員進行讀寫時形成資源爭搶致使程序出現未定義的行爲。一般的作法是在修改共享數據成員的時候進行加鎖--mutex。在使用鎖的時候一般是在對共享數據進行修改以前進行lock操做,在寫完以後再進行unlock操做,進場會出現因爲疏忽致使因爲lock以後在離開共享成員操做區域時忘記unlock,致使死鎖。安全
針對以上的問題,C++11中引入了std::unique_lock與std::lock_guard兩種數據結構。經過對lock和unlock進行一次薄的封裝,實現自動unlock的功能。數據結構
std::mutex mut; void insert_data() { std::lock_guard<std::mutex> lk(mut); queue.push_back(data); } void process_data() { std::unqiue_lock<std::mutex> lk(mut); queue.pop(); }
std::unique_lock 與std::lock_guard都能實現自動加鎖與解鎖功能,可是std::unique_lock要比std::lock_guard更靈活,可是更靈活的代價是佔用空間相對更大一點且相對更慢一點。多線程
經過實現一個線程安全的隊列來講明二者之間的差異。函數
template <typename t=""> class ThreadSafeQueue{ public: void Insert(T value); void Popup(T &value); bool Empety(); private: mutable std::mutex mut_; std::queue<t> que_; std::condition_variable cond_; }; template <typename t=""> void ThreadSafeQueue::Insert(T value){ std::lock_guard<std::mutex> lk(mut_); que_.push_back(value); cond_.notify_one(); } template <typename t=""> void ThreadSafeQueue::Popup(T &value){ std::unique_lock<std::mutex> lk(mut_); cond_.wait(lk, [this]{return !que_.empety();}); value = que_.front(); que_.pop(); } template <typename t=""> bool ThreadSafeQueue::Empty() const{ std::lock_guard<std::mutex> lk(mut_); return que_.empty(); }
上面代碼只實現了關鍵的幾個函數,並使用了C++11新引入的condition_variable條件變量。從Popup與Inert兩個函數看std::unique_lock相對std::lock_guard更靈活的地方在於在等待中的線程若是在等待期間須要解鎖mutex,並在以後從新將其鎖定。而std::lock_guard卻不具有這樣的功能。this
是C++11新引入的功能,lambda表達式,是一種匿名函數。方括號內表示捕獲變量。當lambda表達式返回true時(即queue不爲空),wait函數會鎖定mutex。當lambda表達式返回false時,wait函數會解鎖mutex同時會將當前線程置於阻塞或等待狀態。線程
還存在另外一種讀寫鎖,可是並無引入C++11,可是boost庫提供了對應的實現。讀寫鎖主要適合在於共享數據更新頻率較低,可是讀取共享數據頻率較高的場合。code