Lock Free (無鎖並發)


CAS( compare and swap) 原子操作,保證了如果需要更新的地址沒有被其他進程(線程)改動過,那么它可以安全的寫入。而這也是我們對於某個數據或者數據結構加鎖要保護的內容,保證讀寫的一致性,不出現dirty data。可在循環中不斷執行CAS,如果共享變量沒有改變,那么swap,在當前環境中寫入,否則繼續do-while的Retry-Loop。

1 int compare_and_swap (int* reg, int oldval, int newval) {
2   ATOMIC();
3   int old_reg_val = *reg;
4   if (old_reg_val == oldval) 
5      *reg = newval;
6   END_ATOMIC();
7   return old_reg_val;
8 }

ABA問題最容易發生在lock free算法中的,地址被重用的情況

無鎖相當於“鎖”的粒度變小了,主要是“鎖”HEAD和TAIL這兩個關鍵資源。而不是整個數據結構。

無鎖與自旋鎖比較:

無鎖

自旋鎖

自旋鎖與互斥鎖比較:

1. 自旋鎖不會使線程狀態發生切換,一直處於用戶態,即線程一直都是active的;不會使線程進入阻塞狀態,減少了不必要的上下文切換,執行速度快

2. 互斥鎖在獲取不到鎖的時候會進入阻塞狀態,從而進入內核態,當獲取到鎖的時候需要從內核態恢復,需要線程上下文切換。 (線程被阻塞后便進入內核(Linux)調度狀態,這個會導致系統在用戶態與內核態之間來回切換,嚴重影響鎖的性能)

  • 自旋鎖:線程獲取鎖的時候,如果鎖被其他線程持有,則當前線程將循環等待,直到獲取到鎖。
  • 自旋鎖等待期間,線程的狀態不會改變,線程一直是用戶態並且是活動的(active)。
  • 自旋鎖如果持有鎖的時間太長,則會導致其它等待獲取鎖的線程耗盡CPU。
  • 自旋鎖本身無法保證公平性,同時也無法保證可重入性。
  • 基於自旋鎖,可以實現具備公平性和可重入性質的鎖。
  • TicketLock:采用類似銀行排號叫好的方式實現自旋鎖的公平性,但是由於不停的讀取serviceNum,每次讀寫操作都必須在多個處理器緩存之間進行緩存同步,這會導致繁重的系統總線和內存的流量,大大降低系統整體的性能。
  • CLHLock和MCSLock通過鏈表的方式避免了減少了處理器緩存同步,極大的提高了性能,區別在於CLHLock是通過輪詢其前驅節點的狀態,而MCS則是查看當前節點的鎖狀態。
Mutex主要解決並發實體之間的互斥的問題,而semaphone主要解決並發實體之間的同步問題。針對一些臨界區比較少,處理開銷比較小,而且實時性要求比較高的場景可以使用spin_lock來替代mutex實現互斥, 而如果需要共享的數據只有一個字段,可以使用lock-free的方式來替代spin_lock從而達到更高的性能。
 
條件變量:
用wait和signal實現同步互斥,其中這兩個操作需要用互斥量包裹,互斥鎖+條件變量可以實現讀寫鎖(多個讀鎖可以進入臨界區,只有一個寫鎖進入臨界區,讀寫鎖同時只能有一種進入臨界區)
條件變量是進程中的全局變量(針對線程),信號量是系統中的全局變量(針對進程)

參考博客: 

gaochundong

coolshell

IBM developer

自旋鎖

CAS源碼解讀


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM