如何高效的使用鎖

2021-10-23 13:17:06 字數 1701 閱讀 2319

我們很多時候在使用共享資料的時候,往往會使用鎖來保護,最常用的鎖就是互斥鎖了。如之前的博文介紹的,鎖一般分為:互斥鎖、自旋鎖、讀寫鎖、樂觀鎖等。鎖有這麼多種,那麼我們應該怎麼選擇鎖,以提供更好的效能呢?首先我們得知道加鎖的成本,其次是訪問共享資源衝突的概率,再次是共享資源的特性如讀多寫少。

鎖的實現是有層級的,鎖基本都是基於自旋鎖或者互斥鎖實現的。

互斥鎖加鎖成本更高,當發生併發衝突時,獲取不到鎖的執行緒將會堵塞,而堵塞執行緒往往需要核心的參與,從而導致執行緒獲取鎖失敗時,增加了兩次上下文切換的成本:從執行中切換為休眠,以及鎖釋放時從休眠狀態切換為執行中。上下文切換耗時在幾十納秒到幾微秒之間,或許這段時間比鎖住的**段執行時間還長。

自旋鎖則相反,當獲取鎖失敗時,執行緒不會發生上下文切換,而是進入忙等待。自旋鎖的加鎖是通過cpu提供的cas指令,在使用者態中完成。加鎖流程包括 2 個步驟:第 1 步檢視鎖的狀態,如果鎖是空閒的,第 2 步將鎖設定為當前執行緒持有,故 cas(lock, 0, pid)如果成功,就表示自旋鎖的加鎖操作成功。

如果加鎖的時間比較短並且併發衝突不是很嚴重,那麼自旋鎖等鎖與執行鎖資源的**一般不會發生上下文切換,否則cpu將長時間被忙等待占有,從而導致併發下降,此時我們應該使用互斥鎖。但是當你無法判斷鎖住的**會執行多久時,應該首選互斥鎖。

讀寫鎖由讀鎖與寫鎖組成,當僅讀取共享資源時,使用讀鎖;當需要修改共享資源時,使用寫鎖。寫鎖是一種獨佔鎖,當獲取到寫鎖時,其他執行緒都不能獲取到讀鎖與寫鎖。讀鎖則是一種共享鎖,不同執行緒間可以同時獲取讀鎖。如果共享資源是讀多寫少,則可以用讀寫鎖。

讀寫鎖又可以分為讀優先讀寫鎖、寫優先讀寫鎖與公平讀寫鎖。

讀優先讀寫鎖更強調效率,它期待鎖能被更多的執行緒持有。當執行緒a先持有讀鎖後,即使執行緒b在等待寫鎖,後續前來獲取讀鎖的執行緒c仍然可以立刻加鎖成功,這樣就有 a、c這2個讀執行緒在併發持有鎖,效率更高。但如果讀執行緒源源不斷的來,那麼會導致寫執行緒餓死。

寫優先讀寫鎖則相反,執行緒c獲取讀鎖會失敗,它將被阻塞在獲取鎖的**中,這樣,只要執行緒a釋放讀鎖後,執行緒b馬上就可以獲取到寫鎖。寫優先鎖可以保證寫執行緒不會餓死,但如果新的寫執行緒源源不斷地到來,讀執行緒也可能被餓死。

公平讀寫鎖通過用佇列把請求鎖的執行緒排隊,按照先來後到的順序加鎖即可,當然讀執行緒仍然可以併發,只不過不能插隊到寫執行緒之前。

在讀寫鎖的讀多寫少的場景中,既然是讀多寫少,那麼我們能不能同時利用樂觀鎖與讀寫鎖呢?其實是可以的,這就是stamped_lock。stamped_lock有三種鎖:

1、寫鎖,是個排它鎖或者叫獨佔鎖,同時只有乙個執行緒可以獲取該鎖,當乙個執行緒獲取該鎖後,其它請求的執行緒必須等待,當目前沒有執行緒持有悲觀讀鎖或者寫鎖的時候才可以獲取到該鎖;

2、悲觀讀鎖,是個共享鎖,在沒有執行緒獲取獨佔寫鎖的情況下,同時多個執行緒可以獲取該鎖,如果已經有執行緒持有寫鎖,其他執行緒請求獲取該讀鎖會被阻塞;

3、樂觀讀鎖,是相對於悲觀鎖來說的,在運算元據前並沒有通過cas設定鎖的狀態,如果當前沒有執行緒持有寫鎖,則簡單的返回乙個非0的stamp版本資訊,獲取該stamp後在具體運算元據前還需要呼叫驗證下該stamp是否已經被修改。

寫鎖與悲觀讀鎖類似於讀寫鎖,可以使用互斥鎖實現,也可以使用自旋鎖實現。

那麼怎麼使用stamped_lock:

1、可以先使用樂觀讀鎖獲取乙個stamp並且判斷stamp是否合法,然後將共享資料拷貝到執行緒的使用記憶體中(如棧變數),然後校驗stamp是否改變,如果改變說明有其他執行緒修改了共享變數或者正在修改共享變數,那麼就用悲觀讀鎖獲取讀鎖,否則使用執行緒私有變數儲存的值計算結果。這個是stamp的經典用法。

如何高效的使用STL

一些容器選用法則 1 如果程式要求隨機訪問元素,則應使用vector或deque容器 2 如果程式必須在容器的中間位置插入或刪除元素,則應採用list容器 3 如果程式不是在容器的中間位置,而是在容器首部或尾部插入或刪除元素,則應採用deque容器 4 如果只需要在讀取輸入時在容器的中間位置插入元素...

如何高效的使用 Git

昨天還是執行好好的今天就不行了。被刪了。突然出現了乙個奇怪的 bug,但是沒人知道怎麼回事。如果你出現過上面的任何一種情況,那本篇文章就是為你準備的。除了知道 git add git commit git push 之外,git 中還需要其他重要的技術需要掌握。長遠來看對我們是有幫助的。這裡我將向你...

如何高效的使用 Git

昨天還是執行好好的今天就不行了。被刪了。突然出現了乙個奇怪的 bug,但是沒人知道怎麼回事。如果你出現過上面的任何一種情況,那本篇文章就是為你準備的。除了知道git add,git commit,git push之外,git 中還需要其他重要的技術需要掌握。長遠來看對我們是有幫助的。這裡我將向你展示...