關於SpinLock的更深入理解

0 前言

         之前轉載過一篇闡述spin_lock的博文,但始終理解不深入,記憶不深刻。今天,花了半天閱讀完LDD3的相關章節,有種頓悟的感覺,遂簡要記下自己的理解。Btw,LDD3真心是字字珠璣,沒有半句廢話,而且從這邊書可以看出外國人寫書非常注重前後的呼應,而國內大多數書都是就事論事,沒有體系的感覺,也難以啓發人深入思考。(一不小心又吐嘈了一遍,罪過罪過……)另外,關於LDD3真心適合有一定基礎的人閱讀和思考。

1 正文

         爲什麼設計spin_lock?

         我認爲主要是考慮到使用sem的機制去保護臨界區,實時性太差,不能滿足對實時性有嚴格要求的場景。子問題,爲什麼實時性低,這還要從sem實現原理上分析,sem如果不允許進入臨界區,那麼會放棄CPU切換到其它進程,待進入臨界區的進程釋放鎖後,再切換到該進程。那麼一來一回切換進程的時間開銷,對於實時性來說是種傷害。所以也就有了需要設計一套具有高實時性且能夠支持對臨界區保護的機制方法來取帶sem的機制。

         Spin_lock是怎麼做到的?

         Spin_lock實現的方法,既然需要提高實時性,那麼試圖進入臨界區的進程必然不能放棄CPU,它需要不停地去查找詢問CPU是否可以進入,以便第一時間進入。所以spin_lock就是用這麼一種busy_loop的方式去申請進入。當然這肯定會帶來CPU的使用率下降,但是我們目前需要的實時性,這種sem不能帶來給我們的特點,犧牲點CPU性能又有什麼關係。況且它在使用建議上做了一定約束(後文會提到),做到最大化地減小這種busy loop帶來的影響。

         如何設計實現Spin_lock?

         雖然上面說的非常簡單,就是簡單的busy_loop,但是很多細節需要考慮,爲應用者提出了新的要求,不比使用sem簡單。

首先,我們從處理器架構上考慮,如果是多核系統,處理器核1運行的進程p1在t1時刻進入了臨界區,此時恰巧處理器核2上運行的進程p2在t2時刻,時間方面t1<t2<t1+臨界區運行時間t3,那麼p2只需要靜靜等待,同時不停try即可,待p1出了臨界區,p2會得到立即響應,非常完美。但是,這裏有一個非常重要的假設,整個系統運行在多核處理上,且p1與p2這兩個近乎同一時間需要訪問臨界區的進程又運行在兩個不同的處理器上,這是多麼的巧合啊。那我們隨便考慮一個場景在單核上運行的搶佔式調度策略的內核,那麼假設p1進入臨界區,在還沒有退出時,p2由於優先級更高,進行搶佔,獲得了CPU資源,不停在busy-loop,整個系統鎖死,尷尬!

爲了解決上述問題,一方面,我們要剝奪進入spin_lock的進程運行所在的CPU被搶佔的權利(linux內核本質上是可以被搶佔的),注意強調只需要禁止進入臨界區進程所運行的CPU被搶佔即可。另一方面,我們不能主動放棄CPU,雖然不能被內核其它進程搶佔,但如果該進程主動釋放CPU請求調度,那也是不行的。前者,可以由spin_lock的實現者完成,而後者則是他們對應用的人提出的需求,即不允許spin_lock保護的臨界區代碼有任何休眠釋放CPU的操作,例如copy_from_user、kmalloc等存在風險。

因此爲了解決死鎖,是需要設計者和開發者共同努力完成的。

然後,上述我們只是從處理器架構和內核調度進程策略上分析的結果。接着,我們要從中斷的角度出發去挖掘新的約束。假設進程p1進入臨界區,此時發生中斷,而中斷服務程序也需要進入臨界區,而中斷服務只可能被中斷,所以中斷永遠不可能進入臨界區,再次死鎖。So…解決辦法還是由spin_lock的設計人員來完成,它們會禁止該CPU的中斷功能,同樣需要注意,這裏是以CPU爲單位,而不是所有CPU中斷會被禁止。

這裏稍微總結下:爲了實現可用的不會出現死鎖現象的spin_lock,spin_lock的實現者做了兩件事情,一是禁止了進入臨界區進程被剝奪的權利,二是禁止了運行該進程所在CPU的中斷。而spin_lock的使用者,則需要保證臨界區代碼不調用可能放棄CPU的函數。

如何提高spin_lock的效率?

如上所述可以確定由於spin_lock的使用會浪費CPU資源(因爲busy_loop),所以爲了儘可能地消除負面影響,要求使用者spin_lock所保護的臨界區代碼儘可能精煉簡單。

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