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