C 11之多執行緒 unique lock詳解

2021-10-10 10:57:41 字數 4893 閱讀 7073

目錄

1.unique_lock取代lock_guard

2. unique_lock的第二個引數

2.1 std::adopt_lock

2.2 std::try_to_lock

2.3 std::defer_lock

3. unique_lock的成員函式

3.1 lock(),加鎖

3.2 unlock(),解鎖

3.3 try_lock()

3.4 release()

4. unique_lock所有權的傳遞

c++11中的unique_lock使用起來要比lock_guard更靈活,但是效率會第一點,記憶體的占用也會大一點。同樣,unique_lock也是乙個類模板,但是比起lock_guard,它有自己的成員函式來更加靈活進行鎖的操作。

使用方式和lock_guard一樣,不同的是unique_lock有不一樣的引數和成員函式。它的定義是這樣的:

std::unique_lockmunique(mlock);
這樣定義的話和lock_guard沒有什麼區別,最終也是通過析構函式來unlock。

unique_lock也可以加std::adopt_lock引數,表示互斥量已經被lock,不需要再重複lock。該互斥量之前必須已經lock,提前加鎖,才可以使用該引數。

可以避免一些不必要的等待,會判斷當前mutex能否被lock,如果不能被lock,可以先去執行其他**。這個和adopt不同,不需要自己提前加鎖。舉個例子來說就是如果有乙個執行緒被lock,而且執行時間很長,那麼另乙個執行緒一般會被阻塞在那裡,反而會造成時間的浪費。那麼使用了try_to_lock後,如果被鎖住了,它不會在那裡阻塞等待,它可以先去執行其他沒有被鎖的**。具體實現過程如下:

#include #include std::mutex mlock;

void workpor1(int& s)

else

}}void workpro2(int& s)

else

}}int main()

這個引數表示暫時先不lock,之後手動去lock,但是使用之前也是不允許去lock。一般用來搭配unique_lock的成員函式去使用。下面就列舉defer_lock和一些unique_lock成員函式的使用方法。

當使用了defer_lock引數時,在建立了unique_lock的物件時就不會自動加鎖,那麼就需要借助lock這個成員函式來進行手動加鎖,當然也有unlock來手動解鎖。這個和mutex的lock和unlock使用方法一樣,實現**如下:

#include #include std::mutex mlock;

void workpro1(int& s)

}void workpro2(int& s)

}int main()

還有乙個成員函式是try_lock,和上面的try_to_lock引數的作用差不多,判斷當前是否能lock,如果不能,先去執行其他的**並返回false,如果可以,進行加鎖並返回true,**如下:

void workpro1(int& s) 

else

}}release函式,解除unique_lock和mutex物件的聯絡,並將原mutex物件的指標返回出來。如果之前的mutex已經加鎖,需在後面自己手動unlock解鎖,**如下:

void workpro2(int& s)

}

對越unique_lock的物件來說,乙個物件只能和乙個mutex鎖唯一對應,不能存在一對多或者多對一的情況,不然會造成死鎖的出現。所以如果想要傳遞兩個unique_lock物件對mutex的許可權,需要運用到移動語義或者移動建構函式兩種方法。

移動語義:

std::unique_lockmunique1(mlock);

std::unique_lockmunique2(std::move(munique1));

// 此時munique1失去mlock的許可權,並指向空值,munique2獲取mlock的許可權

移動建構函式:

std::unique_lockrtn_unique_lock()

void work1(int& s)

}

unique_lock是個類模板,工作中,一般lock_guard(推薦使用);lock_guard取代了mutex的lock()和unlock();

unique_lock比lock_guard靈活很多,效率上差一點,記憶體占用多一點。

lock_guard可以帶第二個引數:

std::lock_guardsbguard1(my_mutex1, std::adopt_lock);// std::adopt_lock標記作用;
表示這個

互斥量已經被lock了

(你必須要把互斥量提前lock了 ,否者會報異常);

std::adopt_lock標記的效果就是假設呼叫一方已經擁有了互斥量的所有權(已經lock成功了);通知lock_guard不需要再建構函式中lock這個互斥量了。

unique_lock也可以帶std::adopt_lock標記,含義相同,就是不希望再unique_lock()的建構函式中lock這個mutex。

用std::adopt_lock的前提是,自己需要先把mutex lock上;用法與lock_guard相同。

我們會嘗試用mutex的lock()去鎖定這個mutex,但如果沒有鎖定成功,我也會立即返回,並不會阻塞在那裡;

用這個try_to_lock的前提是你自己不能先lock。例項**如下:

#include#include#include#include#include#includeusing namespace std;

class a

else

}} }

bool outmsglulproc(int &command)

return false;

} //把資料從訊息佇列取出的執行緒

void outmsgrecvqueue()

else

}cout << "end!" << endl; }

private:

std::listmsgrecvqueue;//容器(訊息佇列),代表玩家傳送過來的命令。

std::mutex my_mutex;//建立乙個互斥量(一把鎖)};

int main()

用std::defer_lock的前提是,你不能自己先lock,否則會報異常

std::defer_lock的意思就是並沒有給mutex加鎖:初始化了乙個沒有加鎖的mutex。

我們藉著defer_lock的話題,來介紹一些unique_lock的重要成員函式

defer_lock、lock()與unlock() 例項** 如下 :

void inmsgrecvqueue()

}

嘗試給互斥量加鎖,如果拿不到鎖,返回false,如果拿到了鎖,返回true,這個函式是不阻塞的;例項**如下:

void inmsgrecvqueue()

else

}}

返回它所管理的mutex物件指標,並釋放所有權;也就是說,這個unique_lock和mutex不再有關係。嚴格區分unlock()與release()的區別,不要混淆。

如果原來mutex對像處於加鎖狀態,你有責任接管過來並負責解鎖。(release返回的是原始mutex的指標)。例項**如下:

void inmsgrecvqueue()

}

為什麼有時候需要unlock();因為你lock()鎖住的**段越少,執行越快,整個程式執行效率越高。有人也把鎖頭鎖住的**多少成為鎖的粒度,粒度一般用粗細來描述;

a)鎖住的**少,這個粒度叫細,執行效率高;

b)鎖住的**多,這個粒度叫粗,執行效率低;

要學會盡量選擇合適粒度的**進行保護,粒度太細,可能漏掉共享資料的保護,粒度太粗,影響效率。

選擇合適的粒度是高階程式設計師能力和實力的體現;

std::unique_locksbguard(my_mutex);//所有權概念

sbguard擁有my_mutex的所有權;sbguard可以把自己對mutex(my_mutex)的所有權轉移給其他的unique_lock物件;

所以unique_lock物件這個mutex的所有權是可以轉移,但是不能複製。

std::unique_locksbguard1(my_mutex);

std::unique_locksbguard2(sbguard1);//此句是非法的,複製所有權是非法的

std::unique_locksbguard2(std::move(sbguard));//移動語義,現在先當與sbguard2與my_mutex繫結到一起了

//現在sbguard1指向空,sbguard2指向了my_mutex

方法1 :std::move()

方法2:return std:: unique_lock**如下:

std::unique_lockrtn_unique_lock()	 

void inmsgrecvqueue()

}

C 11 基礎之多執行緒二

include void test pro promise p void test future 此處獲取非同步操作結果使用的是get,當然還有wait以及wait for。函式原型 template class rep,class period std future status wait for...

C 11 多執行緒

新特性之描述 雖然 c 11 會在語言的定義上提供乙個記憶體模型以支援執行緒,但執行緒的使用主要將以 c 11 標準庫的方式呈現。c 11 標準庫會提供型別 thread std thread 若要執行乙個執行緒,可以建立乙個型別 thread 的實體,其初始引數為乙個函式物件,以及該函式物件所需要...

c 11 多執行緒

1.多執行緒的原理 同一時間內,cpu只能處理1條執行緒,只有1條執行緒在工作 執行 多執行緒併發 同時 執行,其實是cpu快速地在多條執行緒之間排程 切換 如果cpu排程執行緒的時間足夠快,就造成了多執行緒併發執行的假象。思考 如果執行緒非常非常多,會發生什麼情況?cpu會在n多執行緒之間排程,c...