歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux綜合 >> Linux內核

spinlock與linux內核調度的關系詳解

關於自旋鎖用法介紹的文章,已經有很多,但有些細節的地方點的還不夠透。我這裡就把我個人認為大家容易有疑問的地方拿出來討論一下。

 

一、自旋鎖(spinlock)簡介

 

自旋鎖在同一時刻只能被最多一個內核任務持有,所以一個時刻只有一個線程允許存在於臨界區中。這點可以應用在多處理機器、或運行在單處理器上的搶占式內核中需要的鎖定服務。

 

二、信號量簡介

 

這裡也介紹下信號量的概念,因為它的用法和自旋鎖有相似的地方。

 

Linux中的信號量是一種睡眠鎖。如果有一個任務試圖獲得一個已被持有的信號量時,信號量會將其推入等待隊列,然後讓其睡眠。這時處理器獲得自由去執行其它代碼。當持有信號量的進程將信號量釋放後,在等待隊列中的一個任務將被喚醒,從而便可以獲得這個信號量。

 

三、自旋鎖和信號量對比

 

在很多地方自旋鎖和信號量可以選擇任何一個使用,但也有一些地方只能選擇某一種。下面對比一些兩者的用法。

 

表1-1自旋鎖和信號量對比

應用場合

信號量or自旋鎖

低開銷加鎖(臨界區執行時間較快)

優先選擇自旋鎖

低開銷加鎖(臨界區執行時間較長)

優先選擇信號量

臨界區可能包含引起睡眠的代碼

不能選自旋鎖,可以選擇信號量

臨界區位於非進程上下文時,此時不能睡眠

優先選擇自旋鎖,即使選擇信號量也只能用

down_trylock非阻塞的方式

 

 

四、自旋鎖與linux內核進程調度關系

 

我們討論下表1-1中的第3種情況(其它幾種情況比較好理解),如果臨界區可能包含引起睡眠的代碼則不能使用自旋鎖,否則可能引起死鎖。

 

那麼為什麼信號量保護的代碼可以睡眠而自旋鎖就不能呢?

 

先看下自旋鎖的實現方法吧,自旋鎖的基本形式如下:

 

spin_lock(&mr_lock);
//臨界區
spin_unlock(&mr_lock);

跟蹤一下spin_lock(&mr_lock)的實現

#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()”,這個調用的功能是“關搶占”(在spin_unlock中 會重新開啟搶占功能)。從中可以看出,使用自旋鎖保護的區域是工作在非搶占的狀態;即使獲取不到鎖,在“自旋”狀態也是禁止搶占的。了解到這,我想咱們應 該能夠理解為何自旋鎖保護的代碼不能睡眠了。試想一下,如果在自旋鎖保護的代碼中間睡眠,此時發生進程調度,則可能另外一個進程會再次調用spinlock保護的這段代碼。而我們現在知道了即使在獲取不到鎖的“自旋”狀態,也是禁止搶占的,而“自旋”又是動態的,不會再睡眠了,也就是說在這個處理器上不會再有進程調度發生了,那麼死鎖自然就發生了。

 

咱們可以總結下自旋鎖的特點:

l 單處理器非搶占內核下:自旋鎖會在編譯時被忽略;

l 單處理器搶占內核下:自旋鎖僅僅當作一個設置內核搶占的開關;

l 多處理器下:此時才能完全發揮出自旋鎖的作用,自旋鎖在內核中主要用來防止多處理器中並發訪問臨界區,防止內核搶占造成的競爭。

 

五、linux搶占發生的時間

 

最後在了解下linux搶占發生的時間,搶占分為用戶搶占和內核搶占。

 

用戶搶占在以下情況下產生:

l 從系統調用返回用戶空間

l 從中斷處理程序返回用戶空間

 

內核搶占會發生在:

l 當從中斷處理程序返回內核空間的時候,且當時內核具有可搶占性;

l 當內核代碼再一次具有可搶占性的時候。(如:spin_unlock時)

l 如果內核中的任務顯式的調用schedule()

l 如果內核中的任務阻塞。

 

基本的進程調度就是發生在時鐘中斷後,並且發現進程的時間片已經使用完了,則發生

進程搶占。通常我們會利用中斷處理程序返回內核空間的時候可以進行內核搶占這個特性來提高一些I/O操作的實時性,如:當I/O事件發生的是時候,對應的中斷處理程序被激活,當它發現有進程在等待這個I/O事件的時候,它會激活等待進程,並且設置當前正在執行進程的need_resched標志,這樣在中斷處理程序返回的時候,調度程序被激活,原來在等待I/O事件的進程(很可能)獲得執行權,從而保證了對I/O事件的相對快速響應(毫秒級)。可以看出,在I/O事件發生的時候,I/O事件的處理進程會搶占當前進程,系統的響應速度與調度時間片的長度無關。

Copyright © Linux教程網 All Rights Reserved