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實現同步互斥,其中這兩個操作需要用互斥量包裹,互斥鎖+條件變量可以實現讀寫鎖(多個讀鎖可以進入臨界區,只有一個寫鎖進入臨界區,讀寫鎖同時只能有一種進入臨界區)
條件變量是進程中的全局變量(針對線程),信號量是系統中的全局變量(針對進程)
參考博客: