讀書筆記(九)-內核同步介紹

存在共享資源(共享一個文件,一塊內存等等)的時候,爲了防止併發訪問時共享資源的數據不一致,引入了同步機制.

主要內容:

  1. 同步的概念
  2. 同步的方法-加鎖
  3. 死鎖
  4. 鎖的粒度


1.同步的概念

瞭解同步之前,先了解另外2個概念:

  • 臨界區-也稱爲臨界段,就是訪問和操作共享數據的代碼段.
  • 競爭條件-2個或2個以上線程在臨界區裏同時執行的時候,就構成了競爭條件.

所謂同步,就是防止在臨界區形成競爭條件.

如果臨界區裏是原子操作(即整個操作完成前都不會被打斷),那麼自然就不會出現競爭條件.

但是在實際應用中,臨界區中的代碼往往不會那麼簡單,所以爲了保持同步,引入了鎖機制.


2.同步的方法-加鎖

爲了給臨界區加鎖,保證臨界區數據的同步,首先了解以下內核中哪些情況下會產生併發.

內核中造成競爭條件的原因:

競爭條件 說明
中斷 中斷隨時會發生,也就會隨時打斷當前執行的代碼.如果中斷和被打斷的代碼在相同的臨界區,就產生了競爭條件
軟中斷和tasklet 軟中斷和tasklet也會隨時被內核喚醒執行,也會像中斷一樣打斷正在執行的代碼
內核搶佔 內核具有搶佔性,發生搶佔時,如果搶佔的線程和被搶佔的線程在相同的臨界區,就產生了競爭條件
睡眠及用戶空間的同步 用戶進程睡眠後,調度程序會喚醒一個新的用戶進程,新的用戶進程和睡眠的進程可能在同一個臨界區中
對稱多處理 2個或多個處理器可以同時執行相同的代碼


爲了在編寫內核代碼時避免出現競爭條件,在編寫代碼之前就要考慮好臨界區在哪,以及怎麼加鎖

在編寫完代碼後再加鎖是非常困難的,很可能還會導致部分代碼重寫.


編寫內核代碼時,時時記着下面這些問題:

  1. 這個數據是不是全局的?除了當前線程以外,其他線程能不能訪問它?
  2. 這個數據會不會在進程上下文或者中斷上下文中共享?它是不是要在兩個不同的中斷處理程序中共享?
  3. 進程在訪問數據時可不可能被搶佔?被調度的新程序會不會訪問同一數據?
  4. 當前進程會不會睡眠(或阻塞)在某些資源上,如果是,它會讓共享資源處於何種狀態?
  5. 怎樣防止數據失控
  6. 如果這個函數又在另一個處理器上被調度將會發生什麼


3.死鎖

死鎖就是所有線程都在互相等待釋放資源,導致誰也無法繼續執行下去.

下面一些簡單的規則可以幫助我們避免死鎖:

  1. 如果有多個鎖的話,儘管確保每個線程都是按相同的順序加鎖,按加鎖相反的順序解鎖.(即加鎖a->b->c,解鎖c->b->a)
  2. 防止發生飢餓.即設置一個超時時間,防止一直等待下去.
  3. 不要重複請求同一個鎖.
  4. 設計應力求簡單.加鎖的方案越複雜越容易出現死鎖.


4.鎖的粒度

在加鎖的時候,不僅要避免死鎖,還需要考慮加鎖的粒度.

鎖的粒度對系統的可擴展性有很大影響,在加鎖的時候,要考慮以下這個鎖是否會被多個線程頻繁的爭用.

如果鎖可能被頻繁爭用,就需要將鎖的粒度細化.

細化後的鎖在多處理器的情況下,性能會有所提升.


舉個例子說明一下:比如給一個鏈表加鎖,同時有A,B,C3和線程頻繁訪問這個鏈表.

那麼當A,B,C3個線程同時訪問這個鏈表時,如果A獲得了鎖,那麼B,C線程只能等待A釋放了鎖才能訪問這個鏈表.


如果A,B,C3個線程訪問的是這個鏈表的不同節點(比如A是修改節點listA,B是刪除節點listB,C是追加節點listC),並且這3個節點不是連續的,那麼3個線程同時運行是不會有問題的.


這種情況下就可以細化這個鎖,把加在鏈表上的鎖去掉,改成把鎖加在鏈表的每個節點上.(也就是鎖粒度的細化)

那麼,上述的情況下,A,B,C3個線程就可以同時訪問各自的節點,特別是多處理器的情況下,性能會有顯著提高.


最後還有一點需要提醒的是,鎖的粒度越細,系統開銷越大,程序也越複雜,所以對於爭用不是很頻繁的鎖,就沒有必要細化了.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章