更新時間:2020-12-16 17:44:00 來源:動力節點 瀏覽3299次
Linux內核同步控制方法有很多,信號量、鎖、原子量、RCU等等,不同的實現方法應用于不同的環境來提高操作系統效率。本文我們就來談談Linux內核5種鎖。
Linux作為多任務系統,當一個進程生成的數據傳輸到另一個進程時,或數據由多個進程共享時,或進程必須彼此等待時,或需要協調資源的使用時,應用程序必須彼此通信。而Linux中鎖的作用就是對臨界區資源的讀寫操作的安全限制。信號量在用戶層可以正常工作,原則上也可以用于解決內核內部的各種鎖問題。但事實并非如此:性能是內核最首先的一個目標,雖然信號量初看起來容易實現,但其開銷對內核來說過大,這也是內核中提供了許多不同的鎖和同步機制的原因。
1.自旋鎖spinlock
自旋鎖的主要特征是使用者在想要獲得臨界區執行權限時,如果臨界區已經被加鎖,那么自旋鎖并不會阻塞睡眠,等待系統來主動喚醒,而是原地忙輪詢資源是否被釋放加鎖,自旋就是自我旋轉,這個名字還是很形象的。自旋鎖有它的優點就是避免了系統的喚醒,自己來執行輪詢,如果在臨界區的資源代碼非常短且是原子的,那么使用起來是非常方便的,避免了各種上下文切換,開銷非常小,因此在內核的一些數據結構中自旋鎖被廣泛的使用。
2.互斥鎖mutex
使用者使用互斥鎖時在訪問共享資源之前對進行加鎖操作,在訪問完成之后進行解鎖操作,誰加鎖誰釋放,其他使用者沒有釋放權限。 加鎖后,任何其他試圖再次加鎖的線程會被阻塞,直到當前進程解鎖。 區別于自旋鎖,互斥鎖無法獲取鎖時將阻塞睡眠,需要系統來喚醒,可以看出來自旋轉自己原地旋轉來確定鎖被釋放了,互斥鎖由系統來喚醒,但是現實并不是那么美好的,因為很多業務邏輯系統是不知道的,仍然需要業務線程執行while來輪詢是否可以重新加鎖。考慮這種情況:解鎖時有多個線程阻塞,那么所有該鎖上的線程都被編程就緒狀態, 第一個變為就緒狀態的線程又執行加鎖操作,那么其他的線程又會進入等待,對其他線程而言就是虛假喚醒。 在這種方式下,只有一個線程能夠訪問被互斥鎖保護的資源。
3.讀寫鎖rwlock
讀寫鎖也叫共享互斥鎖:讀模式共享和寫模式互斥,本質上這種非常合理,因為在數據沒有被寫的前提下,多個使用者讀取時完全不需要加鎖的。讀寫鎖有讀加鎖狀態、寫加鎖狀態和不加鎖狀態三種狀態,當讀寫鎖在寫加鎖模式下,任何試圖對這個鎖進行加鎖的線程都會被阻塞,直到寫進程對其解鎖。
4.RCU鎖
RCU鎖是讀寫鎖的擴展版本,簡單來說就是支持多讀多寫同時加鎖,多讀沒什么好說的,但是對于多寫同時加鎖,還是存在一些技術挑戰的。RCU鎖翻譯為Read Copy Update Lock,讀-拷貝-更新 鎖。Copy拷貝:寫者在訪問臨界區時,寫者將先拷貝一個臨界區副本,然后對副本進行修改;Update更新:RCU機制將在在適當時機使用一個回調函數把指向原來臨界區的指針重新指向新的被修改的臨界區,鎖機制中的垃圾收集器負責回調函數的調用。更新時機:沒有CPU再去操作這段被RCU保護的臨界區后,這段臨界區即可回收了,此時回調函數即被調用。從實現邏輯來看,RCU鎖在多個寫者之間的同步開銷還是比較大的,涉及到多份數據拷貝,回調函數等,因此這種鎖機制的使用范圍比較窄,適用于讀多寫少的情況,如網絡路由表的查詢更新、設備狀態表更新等,在業務開發中使用不是很多。
5.可重入鎖和不可重入鎖
Windows下的Mutex和Critical Section是可遞歸的。Linux下的pthread_mutex_t鎖默認是非遞歸的。在Linux中可以顯式設置PTHREAD_MUTEX_RECURSIVE屬性,將pthread_mutex_t設為遞歸鎖避免這種場景。 同一個線程可以多次獲取同一個遞歸鎖,不會產生死鎖。而如果一個線程多次獲取同一個非遞歸鎖,則會產生死鎖。
以上提到的linux內核5種鎖,是linux內核中起著很重要的作用,Linux內核提供了各種鎖選項,分別優化不同的內核數據使用模式。除了鎖之外,還有信號量、原子量、RCU等等,我們可以在本站的Linux教程中找到相關的章節,具體介紹這些Linux內核同步控制方法的使用。
0基礎 0學費 15天面授
有基礎 直達就業
業余時間 高薪轉行
工作1~3年,加薪神器
工作3~5年,晉升架構
提交申請后,顧問老師會電話與您溝通安排學習