多線程 unique_lock的使用 unique_lock的特點: 1,靈活。可以在創建unique_lock的實例時,不鎖,然後手動調用lock_a.lock()函數,或者std::lock(lock_a, …),來上鎖。當unique_lock的實例被析構時,會自動調用unlock函數,釋放鎖 ...
多線程 unique_lock的使用
unique_lock的特點:
1,靈活。可以在創建unique_lock的實例時,不鎖,然後手動調用lock_a.lock()函數,或者std::lock(lock_a, …),來上鎖。當unique_lock的實例被析構時,會自動調用unlock函數,釋放鎖。
unique_lock<mutex> lock_a(d1.m, std::defer_lock);
2,unique_lock的實例可以調用unlock函數。這個意味著,在unique_lock的實例銷毀前,你可以有選擇的在程式的分支釋放鎖。持有鎖的時間比所需時間更長,可能會導致性能下降,因為其他等待該鎖的線程,被阻止運行的時間超過了所需的時間。
註意:有個弊端,當不擁有鎖的時候,調用了unlock成員方法,程式崩潰。崩潰信息如下:
terminate called after throwing an instance of 'std::system_error'
what(): Operation not permitted
Aborted (core dumped)
3,可以在作用域之間轉移鎖的所有權。右值的話,會自動被轉移;左值的話,必須手動調用std::move()函數,來進行鎖的所有權的轉移。
通常使用這種模式,是在待鎖定的互斥元依賴於程式的當前狀態,或者依賴於傳遞給返回std::unique_lock對象的函數的地方。
例子:關於上述第一點和第二點的
#include <list>
#include <iostream>
#include <mutex>
#include <algorithm>
#include <thread>
#include <unistd.h>
using namespace std;
class data_protect;
void swap(data_protect& , data_protect& );
//是線程安全的
class data_protect{
friend void swap(data_protect& , data_protect& );
private:
list<int> alist{1,2};
mutex m;
public:
void add_list(int val){
//操作雙向鏈表時,加鎖了
lock_guard<mutex> g(m);
alist.push_back(val);
}
bool contains(int val){
//操作雙向鏈表時,加鎖了
lock_guard<mutex> g(m);
return find(alist.begin(), alist.end(), val) != alist.end();
}
};
void swap(data_protect& d1, data_protect& d2){
//if(d1 == d2) return;
//造成死鎖
//d1.add_list(11);
unique_lock<mutex> lock_a(d1.m, std::defer_lock);
unique_lock<mutex> lock_b(d2.m, std::defer_lock);
std::lock(lock_a, lock_b);
swap(d1.alist, d2.alist);
//有unlock成員函數,並可以手動調用unlock函數
//如果沒有持有鎖,就調用unlock成員函數就會導致程式崩潰。所以要檢查是否擁有鎖。
if(lock_a.owns_lock() && lock_b.owns_lock()){
lock_a.unlock();
lock_b.unlock();
}
}
int main(){
data_protect d1, d2;
swap(d1, d2);
d2.add_list(11);
}
例子:關於上述的第三點
#include <mutex>
std::unique_lock<std::mutex> getlock(){
std::mutex sm;
std::unique_lock<std::mutex> lk(sm);
//prepare_data();
return lk;//因為lk是右值,所以自動調用了std::move函數,把鎖的所有權轉移了出去。
}
void process_data(){
std::unique_lock<std::mutex> lk(getlock());
//do_something();
}
int main(){
process_data();
}