linux 信号量锁 内核,Linux内核中锁机制之信号量、读写信号量
在上一篇博文中筆者分析了關于內存屏障、讀寫自旋鎖以及順序鎖的相關內容,本篇博文將著重討論有關信號量、讀寫信號量的內容。
六、信號量
關于信號量的內容,實際上它是與自旋鎖類似的概念,只有得到信號量的進程才能執行臨界區的代碼;不同的是獲取不到信號量時,進程不會原地打轉而是進入休眠等待狀態。它的定義是include\linux\semaphore.h文件中,結構體如圖6.1所示。其中的count變量是計數作用,通過使用lock變量實現對count變量的保護,而wait_list則是對申請信號量的進程維護的等待隊列。
圖6.1??????信號量的結構體定義
我們首先看下它是如何使用的,首先定義一個信號量,然后初始化信號量,它包括兩種方法。如圖6.2所示。方法1:簡單的初始化,定義信號量的個數由val決定,實際上val值即是賦給信號量結構體中的count變量;方法2是直接將結構體中count值設置成1,此時信號量可用于實現進程間的互斥量。注意:對于信號量的初始化函數Linux最新版本存在變化,本文所采用的Linux版本已不存在如init_MUTEX和init_MUTEX_LOCKED等初始化函數,同時也更換了名字等,這點讀者在閱讀的時候需要下,因此筆者建議以后在編程中遇到需要使用信號量的時候盡量采用sema_init(struct semaphore *sem, int val)函數,因為這個函數就目前為止從未發生變化。
圖6.2??????信號量的初始函數
下面我們討論如何獲得信號量,它主要包括三個函數,第一個函數表示當信號申請不到時會進程會休眠;對于第二個函數來說,它表示如果當進程因申請不到信號量而進入睡眠后,能被信號打斷,這里所說的信號是指進程間通信的信號,比如我們的Ctrl+C,但這時候這個函數的返回值不為0;第三個函數表示信號量無論是否獲得,都將立即返回,但返回值會根據是否申請成功而定,同時這個函數也不會導致睡眠。最后的up函數,這個還是很好理解的,就是釋放信號量,進而喚醒隊列中的等待信號量的進程。函數如圖6.3所展示一般。
圖6.3??????信號量的獲得和釋放函數
接下來筆者將舉幾個例子,依次如圖6.4,圖6.5所示。圖6.4的例子仍是實現一個設備只能被一個進程打開。例子很簡單,這里便不再細說,主要體現到底如何使用信號量。如圖6.4所展示。
圖6.4??????信號量的使用示例
如圖6.5實現的是進程間的同步問題。實際上,當把信號量的初始值為0,則可以實現同步了。正如圖6.5所展示一般,對于執行單元A而言,如果執行單元B不執行up函數,執行單元A就因為申請不到進程而睡眠,直至up函數被調用,所以執行代碼b前必須等到執行單元B執行完代碼c。相信這個內容在操作系統課程都均有提及。
圖6.5??????信號量實現同步示例
討論過示例后,相信讀者對于信號量的使用有了比較好的了解。下面讓我們來簡單的討論下它的實現機制。通過了解信號量的結構體,可以發現結構體中除了使用自旋鎖機制外,就是count值的變化(這一點先前已提及)。它的源碼如圖6.6,圖6.7所示。
圖6.6??信號量down函數內核源碼圖6.7??信號量up函數內核源碼
從源碼中可以看到信號量利用自旋鎖的相關函數實現了對count變量的保護,通過判斷變量是否大于0以及自增減來實現信號量的申請和釋放。也是因為這一點,所以信號量能夠實現同步機制。
另外,關于源碼中的__down和__up函數的實現內容,它們其實是維護申請信號量的進程的鏈表隊列(增加、刪除操作),以及進程調度方面的一些信息(超時機制),從而讓進程實現休眠。由于其中的源碼量較為龐大,涉及的內容也較多,故這里不再深入討論,感興趣的可以查閱相關資料。
關于信號量的內容還有一點需要提及,我們知道信號量時進程級的,因此對于它的使用必然是當占用資源較長時間的時候。這點在使用信號量的使用需要重點考慮,反之,則容易影響程序的性能等。OK,至此,關于信號量的內容即討論到此。
七、讀寫信號量
接下來筆者將討論有關讀寫信號量的內容,這部分是較難的一部分,需分析較多的源碼。同樣,我們首先看下它主要能夠做些什么:讀寫信號量與信號量的關系如同自旋鎖與讀寫自旋鎖的關系,它允許N個讀操作同時訪問共享資源,但最多只能有一個寫操作。它的定義位置是在arch\x86\include\asm\rwsem.h以及kernel\rwsem.c中。關于它的結構體的定義,如圖7.1所示。顯然,它的結構體定義和信號量的結構體定義如出一轍。
圖7.1??????讀寫信號量的結構體實現
而后了解下它的具體使用方法,如圖7.2所展示的函數。同其它鎖機制類似,它所提供的接口函數也是較為簡單,包括這些函數能實現的功能都差不了多少。
圖7.2??????讀寫信號量的接口函數
在了解讀寫信號量的定義和使用后,接下來讀者將討論的具體源碼實現。它的具體實現是采用匯編實現,比較繞,需配合源碼來一一說明,源碼次序依次如圖7.3至圖7.8所示。為便于分析,下面源碼只給出最為關鍵的內容。
對于圖7.3所展示的內容主要是讀寫信號量中需要使用的一些宏定義,具體為何取這個值筆者就不大了解了,后續研究深入了可能會有所體會。
圖7.3??????讀寫自旋鎖的內核源碼
圖7.4??????讀寫自旋鎖的內核源碼
圖7.5??????讀寫自旋鎖的內核源碼
圖7.4和同7.5所示源碼主要體現了讀鎖和寫鎖的實現內容。實際上還是利用test指令檢測count變量的值來實現。申請成功的內容好理解,其中的xadd指令表示將原操作數和目的操作數值相交換,而后相加保存入目的操作數。一旦讀寫信號量申請失敗,則需要跳轉到如圖7.6,圖7.7所示的源碼中。其中圖7.6,圖7.7中所示的源碼沒多少內容,最后還是跳轉到rwsem_down_read_failed和rwsem_down_write_failed函數中,通過匯編源碼保存改變相應存儲變量的寄存器,從而再次返回到C代碼中,如圖7.8所示的源碼中。由于筆者能力有限,對于圖7.8所示的源碼內容中調用的rwsem_down_write_failed函數被沒有研究透,故這里并未進一步深入研究。
至此,關于讀寫信號量的內容討論基本結束,確實由于筆者能力有限,關于讀寫信號量的內容以及本博文的系列內容,讀者可進一步深入研究,并歡迎討論。共同進步。
圖7.6??讀寫自旋鎖的內核源碼圖7.7??讀寫自旋鎖的內核源碼
圖7.8??????讀寫自旋鎖的內核源碼
出于文章篇幅的限制,本篇博文到此結束,后續將會給出《大話Linux內核中鎖機制之完成量、互斥量》,感興趣的讀者可繼續閱讀后一篇博文。由于筆者水平所限,博文中難免有出錯之處,歡迎讀者指出,大家相互討論,共同進步。
來源:oschina
鏈接:https://my.oschina.net/u/4280386/blog/4238578
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的linux 信号量锁 内核,Linux内核中锁机制之信号量、读写信号量的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《仙境传说RO:新启航》皮里恩讨伐攻略
- 下一篇: 西游笔绘西行牛魔王技能强度解析