1、unique_lock取代lock_guard
unique_lock 是一個(gè)類模板。
unique_lock 比 lock_guard 靈活很多(多出來很多用法),效率差一點(diǎn),內(nèi)存占用多一些。
使用:unique_lock<mutex> myUniLock(myMutex);
2、unique_lock的第二個(gè)參數(shù)
2.1 std::adopt_lock:
std::adopt_lock:標(biāo)記作用,表示這個(gè)互斥量已經(jīng)被lock()(方便記憶:已經(jīng)被lock()收養(yǎng)了,不需要再次lock() ),即不需要在構(gòu)造函數(shù)中l(wèi)ock這個(gè)互斥量了。
前提:必須提前l(fā)ock,否則會(huì)出錯(cuò)
lock_guard中也可以用這個(gè)參數(shù)
2.2 std::try_to_lock:
- 嘗試用mutex的lock()去鎖定這個(gè)mutex,但如果沒有鎖定成功,會(huì)立即返回,不會(huì)阻塞在那里;
- 使用try_to_lock的原因是防止其他的線程鎖定mutex太長時(shí)間,導(dǎo)致本線程一直阻塞在lock 這個(gè)地方
前提:不能提前l(fā)ock();
owns_lock()方法判斷是否拿到鎖,如拿到返回true
實(shí)例:
假設(shè)線程1 執(zhí)行下例代碼時(shí),先鎖定互斥量myMutex1,然后暫停了2s,才繼續(xù)執(zhí)行程序。線程1執(zhí)行的代碼如下
bool outMsgProc(int &num)
{
unique_lock<mutex> muGuard(myMutex1);
chrono::milliseconds time(2000); //線程暫停2s
this_thread::sleep_for(time);
if (!myList.empty())
{
num = myList.front();
myList.pop_front();
return true;
}
return false;
}
在此期間,如果線程2也嘗試鎖定myMutex1,就只能阻塞,直到線程1釋放鎖后,才能繼續(xù)執(zhí)行。線程2執(zhí)行的代碼如下:
void InMsg()
{
for (int i = 0; i < 10000; i++)
{
cout << "插入元素: " << i << endl;
unique_lock<mutex> muGuard(myMutex1);
myList.push_back(i);
}
}
顯然,這樣的程序效率不高。線程2花費(fèi)了太多的時(shí)間等待。
我們考慮使用try_to_lock,線程嘗試獲取鎖,如果沒有鎖定成功,它不會(huì)阻塞在那里,可以去執(zhí)行其他代碼。改進(jìn)后的代碼如下:
void InMsg()
{
for (int i = 0; i < 10000; i++)
{
cout << "插入元素: " << i << endl;
unique_lock<mutex> muGuard(myMutex1, try_to_lock);
if (muGuard.owns_lock())// 判斷是否拿到鎖
{
myList.push_back(i);
}
else
{
//沒有拿到鎖時(shí),執(zhí)行的代碼
}
}
}
2.3 std::defer_lock:
- 如果沒有第二個(gè)參數(shù)就對(duì)mutex進(jìn)行加鎖,加上defer_lock是始化了一個(gè)沒有加鎖的mutex
- 不給它加鎖的目的是以后可以調(diào)用unique_lock的一些方法
- 前提:不能提前l(fā)ock
3、unique_lock的成員函數(shù)(前三個(gè)與std::defer_lock聯(lián)合使用)
3.1 lock():加鎖。
unique_lock<mutex> muGuard(myMutex, defer_lock);
muGuard.lock();//手動(dòng)加鎖
不用自己unlock();
3.2 unlock():解鎖。
unique_lock<mutex> muGuard(myMutex, defer_lock);
muGuard.lock();
//處理一些共享代碼
muGuard.unlock();
//臨時(shí)處理一些非共享代碼
muGuard.lock();
//處理一些共享代碼,處理完之后,自動(dòng)解鎖
3.3 try_lock():嘗試給互斥量加鎖
try_to_lock是unique_lock的第二個(gè)參數(shù),try_lock()是unique_lock()的成員變量。
如果拿不到鎖,返回false,否則返回true(然后上鎖)。
unique_lock<mutex>muGuard(myMutex, defer_lock);
//mutex1.lock();//自動(dòng)解鎖
if (muGuard.try_lock() == true) {
cout << "插入數(shù)據(jù): " << num << endl;
test_list.push_back(num);
}
else {
cout << "in_list()執(zhí)行,但沒有拿到鎖" << num << endl;
}
3.4 release():
release():就是解除綁定,返回它所管理的mutex對(duì)象的指針,并釋放所有權(quán)。
-
unique_lock<mutex>muGuard(myMutex1);
相當(dāng)于把myMutex(mutex對(duì)象)和 muGuard綁定在了一起 -
mutex* ptx =muGuard.release();
也就是說 muGuard和mutex不在有聯(lián)系,后續(xù)myMutex所有權(quán)由ptx接管,如果原來mutex對(duì)象處理加鎖狀態(tài),就需要ptx在以后進(jìn)行解鎖了。
for (int num = 0; num < 10000; num++) {
unique_lock<mutex> muGuard(myMutex);
mutex* ptx = muGuard.release();//解除myMutex1(mutex對(duì)象)和 muGuard綁定
//操作事務(wù)
test_list.push_back(num);
ptx->unlock();//myMutex1所有權(quán)由ptx接管,由ptx進(jìn)行解鎖
}
lock的代碼段越少,執(zhí)行越快,整個(gè)程序的運(yùn)行效率越高。
- 鎖住的代碼少,叫做粒度細(xì),執(zhí)行效率高;
- 鎖住的代碼多,叫做粒度粗,執(zhí)行效率低;
-只鎖定共享的數(shù)據(jù)
4.unique_lock所有權(quán)的傳遞
unique_lock<mutex> muGuard1(myMutex);
把myMutex1和muGuard綁定在了一起,也就是muGuard擁有myMutex1的所有權(quán)文章來源:http://www.zghlxwxcb.cn/news/detail-655872.html
4.1 使用move轉(zhuǎn)移
unique_lock<mutex> muGuard2(std::move(muGuard1));
之前muGuard1擁有myMutex的所有權(quán),muGuard1可以把自己對(duì)myMutex的所有權(quán)轉(zhuǎn)移,但是不能復(fù)制。現(xiàn)在muGuard2擁有myMutex的所有權(quán)。文章來源地址http://www.zghlxwxcb.cn/news/detail-655872.html
4.2. 在函數(shù)中return一個(gè)臨時(shí)變量,也可以實(shí)現(xiàn)轉(zhuǎn)移
unique_lock<mutex> aFunction()
{
unique_lock<mutex> tmpguard(myMutex);
//移動(dòng)構(gòu)造函數(shù)那里講從函數(shù)返回一個(gè)局部的unique_lock對(duì)象是可以的
//返回這種局部對(duì)象會(huì)導(dǎo)致系統(tǒng)生成臨時(shí)的unique_lock對(duì)象,并調(diào)用unique_lock的移動(dòng)構(gòu)造函數(shù)
return tmpguard;
}
// 然后就可以在外層調(diào)用,在muGuard2具有對(duì)myMutex的所有權(quán)
std::unique_lock<std::mutex> muGuard2 = aFunction();
到了這里,關(guān)于C++11并發(fā)與多線程筆記(6) unique_lock(類模板)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!