第九章 內核同步介紹

1. 隨着2.6版內核的出現,Linux內核已經發展成搶佔式內核,如果不加保護,調度程序可以在任何時刻搶佔正在運行的內核代碼,重新調度其他的進程執行

2. 臨界區或者臨界段:訪問和操作共享數據的代碼段

3. 如果兩個執行線程(指代的是任何正在執行的代碼,如一個在內核執行進程、一個中斷處理程序或者內核線程)處於同一個臨界區中同時執行,就成它是競爭條件(race conditions)

4. 避免併發和防止競爭條件稱爲同步(synchronization)。

5. 忙等待:反覆處於一個循環中,不斷檢測狀態,等待鎖變爲可用

6. 鎖是採用原子操作實現的,而原子操作不存在競爭。

7. 用戶空間併發

  • 用戶程序會被調度程序搶佔和重新調度,是僞併發

  • 信號處理的異步發生,是僞併發

  • 對稱多處理器的機器會導致多個進程真正地在臨界區中同時執行,是真併發

8. 內核空間的併發

  • 中斷——中斷幾乎可以在任何時刻異步發生,也就可能隨時打斷當前正在執行的代碼

  • 軟中斷和tasklet——內核能在任何時刻喚醒或調度軟中斷和tasklet,打斷當前正在執行的代碼

  • 內核搶佔——因爲內核具有搶佔性,故內核中的任務可能會被另一個任務搶佔

  • 睡眠及與用戶空間的同步——在內核執行的進程可能會睡眠,這就會喚醒調度程序,從而導致調度一個新的用戶程序執行

  • 對稱多處理——兩個或多個處理器可以同時執行代碼。兩個處理器絕對不能同時訪問同一共享數據

9. 在編寫代碼的開始階段就要設計恰當的鎖,而不是事後纔想到

10. 中斷安全代碼(interrupt-safe):在中斷處理程序中能避免併發訪問的安全代碼

11. SMP安全代碼(SMP-safe):在對稱多處理的機器中能避免併發訪問的安全代碼

12. 搶佔安全代碼(preempt-safe):在內核搶佔時能避免併發訪問的安全代碼

13. 加鎖保護的對象:要給數據而不是給代碼加鎖

14. 在編寫內核代碼時要考慮如下幾個問題:

  • 這個數據是不是全局的?除了當前線程外,其他線程能不能訪問它?

  • 這個數據會不會在進程上下文和中斷上下文中共享?它是不是要在兩個不同的中斷處理程序中共享?

  • 進程在訪問數據時可不可能被搶佔?被調度的新進程會不會訪問同一數據?

  • 當前進程會不會睡眠在某些資源上,如果是,它會讓共享數據處於何種狀態?

  • 怎樣防止數據失控?

  • 如果這個函數又在另一個處理器上被調度將會發生什麼呢?

  • 如何確保代碼遠離併發威脅呢?

15. 死鎖

  • 有一個或多個執行線程和一個或多個資源(如某個鎖),每個線程都在等待其中的一個資源,但所有的資源都已經被佔用了。所有線程都在相互等待,但它們永遠不會釋放已經佔有的資源。於是任何線程都無法繼續,死鎖便發生了。

  • 防止死鎖:

    • 按順序加鎖——使用嵌套的鎖時必須保證以相同的順序獲取鎖,可以阻止擁抱類型的死鎖。最好能記錄下鎖的順序,以便其他人也能按照次順序使用。在釋放鎖的時候,最好以獲取鎖的相反順序進行。

    • 防止發生飢餓。如設置等待超時,或者try lock

    • 不要重複請求同一個鎖

    • 設計力求簡單——越複雜的加鎖方案越能造成死鎖

16. 加鎖粒度:描述加鎖保護的數據規模

  • 當鎖正在被佔用時,有其他線程試圖獲得該鎖,這個被稱爲鎖的爭用。

  • 當鎖爭用嚴重時,加鎖太粗會降低可擴展性;而鎖爭用不明顯時,加鎖過細會加大系統開銷,帶來浪費。這兩種情況都會降低系統系能。





原文地址:https://www.cnblogs.com/pengdonglin137/p/5839568.html