臨界區:訪問和操作共享數據的代碼段
如果兩個執行線程有可能處于同一個臨界區中同時執行,那么就稱其為競爭條件
避免并發和防止競爭條件稱為同步。
加鎖
鎖是采用原子操作實現的,而原子操作不存在競爭。
造成并發執行的原因:
- 用戶空間:
- 用戶程序會被調度程序搶占和重新調度
- 信號處理是異步發生的
- 內核空間:
- 中斷
- 軟中斷和tasklet
- 內核搶占
- 睡眠及與用戶空間的同步
- 對稱多處理
真正用鎖來保護共享資源并不困難,但辨認真正需要共享的數據和相應的臨界區,才是真正有挑戰的地方。因此,在編碼的開始階段就要設計恰當的鎖。大多數內核數據結構都需要加鎖。如果有其他執行線程可以訪問數據,那么就給這些數據加上某種形式的鎖;如果任何其他什么東西都能看到數據,那么就要鎖住它。注意:要給數據而不是代碼加鎖。
- 中斷安全代碼:在中斷處理程序中能避免并發訪問的安全代碼
- SMP安全代碼:在對稱多處理的機器中能避免并發訪問的安全代碼
- 搶占安全代碼:在內核搶占時能避免并發訪問的安全代碼
死鎖
死鎖的產生需要一定條件:要有一個或多個執行線程和一個或多個資源,每個線程都在等待其中一個資源,但所有資源都已經被占用了。所有線程都在互相等待,但永遠不會釋放已經占有的資源。于是所有線程都無法繼續,發生了死鎖。
避免死鎖的一些簡單規則:
- 按順序加鎖
- 防止發生饑餓
- 不要重復請求同一個鎖
- 設計應力求簡單
爭用和擴展性
加鎖粒度用來描述加鎖保護的數據規模。
鎖的爭用(lock contention),簡稱爭用,是指當鎖正在被占用時,有其他線程試圖獲得該鎖。
當鎖爭用嚴重時,加鎖太粗會降低可擴展性;而鎖爭用不明顯時,加鎖過細會加大系統開銷,帶來浪費。這兩種情況都會造成系統性能下降。