spinlock與linux內(nèi)核調(diào)度的關(guān)系
作者:劉洪濤,華清遠(yuǎn)見(jiàn)嵌入式培訓(xùn)中心高級(jí)講師,ARM公司授權(quán)ATC講師。
關(guān)于自旋鎖用法介紹的文章,已經(jīng)有很多,但有些細(xì)節(jié)的地方點(diǎn)的還不夠透。我這里就把我個(gè)人認(rèn)為大家容易有疑問(wèn)的地方拿出來(lái)討論一下。
一、自旋鎖(spinlock)簡(jiǎn)介
自旋鎖在同一時(shí)刻只能被最多一個(gè)內(nèi)核任務(wù)持有,所以一個(gè)時(shí)刻只有一個(gè)線程允許存在于臨界區(qū)中。這點(diǎn)可以應(yīng)用在多處理機(jī)器、或運(yùn)行在單處理器上的搶占式內(nèi)核中需要的鎖定服務(wù)。
二、信號(hào)量簡(jiǎn)介
這里也介紹下信號(hào)量的概念,因?yàn)樗挠梅ê妥孕i有相似的地方。
Linux中的信號(hào)量是一種睡眠鎖。如果有一個(gè)任務(wù)試圖獲得一個(gè)已被持有的信號(hào)量時(shí),信號(hào)量會(huì)將其推入等待隊(duì)列,然后讓其睡眠。這時(shí)處理器獲得自由去執(zhí)行其它代碼。當(dāng)持有信號(hào)量的進(jìn)程將信號(hào)量釋放后,在等待隊(duì)列中的一個(gè)任務(wù)將被喚醒,從而便可以獲得這個(gè)信號(hào)量。
三、自旋鎖和信號(hào)量對(duì)比
在很多地方自旋鎖和信號(hào)量可以選擇任何一個(gè)使用,但也有一些地方只能選擇某一種。下面對(duì)比一些兩者的用法。
表1-1自旋鎖和信號(hào)量對(duì)比
四、自旋鎖與linux內(nèi)核進(jìn)程調(diào)度關(guān)系
我們討論下表1-1中的第3種情況(其它幾種情況比較好理解),如果臨界區(qū)可能包含引起睡眠的代碼則不能使用自旋鎖,否則可能引起死鎖。
那么為什么信號(hào)量保護(hù)的代碼可以睡眠而自旋鎖就不能呢?
先看下自旋鎖的實(shí)現(xiàn)方法吧,自旋鎖的基本形式如下:
spin_lock(&mr_lock);
//臨界區(qū)
spin_unlock(&mr_lock);
跟蹤一下spin_lock(&mr_lock)的實(shí)現(xiàn)
#define spin_lock(lock) _spin_lock(lock)
#define _spin_lock(lock) __LOCK(lock)
#define __LOCK(lock)
do { preempt_disable(); __acquire(lock); (void)(lock); } while (0)
注意到“preempt_disable()”,這個(gè)調(diào)用的功能是“關(guān)搶占”(在spin_unlock中會(huì)重新開(kāi)啟搶占功能)。從中可以看出,使用自旋鎖保護(hù)的區(qū)域是工作在非搶占的狀態(tài);即使獲取不到鎖,在“自旋”狀態(tài)也是禁止搶占的。了解到這,我想咱們應(yīng)該能夠理解為何自旋鎖保護(hù)的代碼不能睡眠了。試想一下,如果在自旋鎖保護(hù)的代碼中間睡眠,此時(shí)發(fā)生進(jìn)程調(diào)度,則可能另外一個(gè)進(jìn)程會(huì)再次調(diào)用spinlock保護(hù)的這段代碼。而我們現(xiàn)在知道了即使在獲取不到鎖的“自旋”狀態(tài),也是禁止搶占的,而“自旋”又是動(dòng)態(tài)的,不會(huì)再睡眠了,也就是說(shuō)在這個(gè)處理器上不會(huì)再有進(jìn)程調(diào)度發(fā)生了,那么死鎖自然就發(fā)生了。
咱們可以總結(jié)下自旋鎖的特點(diǎn):
● 單處理器非搶占內(nèi)核下:自旋鎖會(huì)在編譯時(shí)被忽略;
● 單處理器搶占內(nèi)核下:自旋鎖僅僅當(dāng)作一個(gè)設(shè)置內(nèi)核搶占的開(kāi)關(guān);
● 多處理器下:此時(shí)才能完全發(fā)揮出自旋鎖的作用,自旋鎖在內(nèi)核中主要用來(lái)防止多處理器中并發(fā)訪問(wèn)臨界區(qū),防止內(nèi)核搶占造成的競(jìng)爭(zhēng)。
五、linux搶占發(fā)生的時(shí)間
最后在了解下linux搶占發(fā)生的時(shí)間,搶占分為用戶(hù)搶占和內(nèi)核搶占。
用戶(hù)搶占在以下情況下產(chǎn)生:
● 從系統(tǒng)調(diào)用返回用戶(hù)空間
● 從中斷處理程序返回用戶(hù)空間
內(nèi)核搶占會(huì)發(fā)生在:
● 當(dāng)從中斷處理程序返回內(nèi)核空間的時(shí)候,且當(dāng)時(shí)內(nèi)核具有可搶占性;
● 當(dāng)內(nèi)核代碼再一次具有可搶占性的時(shí)候。(如:spin_unlock時(shí))
● 如果內(nèi)核中的任務(wù)顯式的調(diào)用schedule()
● 如果內(nèi)核中的任務(wù)阻塞。
基本的進(jìn)程調(diào)度就是發(fā)生在時(shí)鐘中斷后,并且發(fā)現(xiàn)進(jìn)程的時(shí)間片已經(jīng)使用完了,則發(fā)生進(jìn)程搶占。通常我們會(huì)利用中斷處理程序返回內(nèi)核空間的時(shí)候可以進(jìn)行內(nèi)核搶占這個(gè)特性來(lái)提高一些I/O操作的實(shí)時(shí)性,如:當(dāng)I/O事件發(fā)生的是時(shí)候,對(duì)應(yīng)的中斷處理程序被激活,當(dāng)它發(fā)現(xiàn)有進(jìn)程在等待這個(gè)I/O事件的時(shí)候,它會(huì)激活等待進(jìn)程,并且設(shè)置當(dāng)前正在執(zhí)行進(jìn)程的need_resched標(biāo)志,這樣在中斷處理程序返回的時(shí)候,調(diào)度程序被激活,原來(lái)在等待I/O事件的進(jìn)程(很可能)獲得執(zhí)行權(quán),從而保證了對(duì)I/O事件的相對(duì)快速響應(yīng)(毫秒級(jí))??梢钥闯?,在I/O事件發(fā)生的時(shí)候,I/O事件的處理進(jìn)程會(huì)搶占當(dāng)前進(jìn)程,系統(tǒng)的響應(yīng)速度與調(diào)度時(shí)間片的長(zhǎng)度無(wú)關(guān)。
“本文由華清遠(yuǎn)見(jiàn)http://www.embedu.org/index.htm提供”
華清遠(yuǎn)見(jiàn)