天天看點

信号量和自旋鎖的差别

(1)核心同步措施

      為了避免并發,防止競争。核心提供了一組同步方法來提供對共享資料的保護。

      Linux 使用的同步機制可以說從2.0到2.6以來不斷發展完善。從最初的原子操作,到後來的信号量,從大核心鎖到今天的自旋鎖。這些同步機制的發展伴随Linux從單處理器到對稱多處理器的過度;伴随着從非搶占核心到搶占核心的過度。鎖機制越來越有效,也越來越複雜。

      目前來說核心中原子操作多用來做計數使用,其它情況最常用的是兩種鎖以及它們的變種:一個是自旋鎖,另一個是信号量。我們下面就來着重介紹一下這兩種鎖機制。

(2)自旋鎖

      自旋鎖是專為防止多處理器并發而引入的一種鎖,它在核心中大量應用于中斷處理等部分(對于單處理器來說,防止中斷進行中的并發可簡單采用關閉中斷的方式,不需要自旋鎖)。自旋鎖最多隻能被一個核心任務持有,如果一個核心任務試圖請求一個已被占用(已經被持有)的自旋鎖,那麼這個任務就會一直進行忙循環——旋轉——等待鎖重新可用。要是鎖未被占用,請求它的核心任務便能立刻得到它并且繼續進行。自旋鎖可以在任何時刻防止多于一個的核心任務同時進入臨界區,是以這種鎖可有效地避免多處理器上并發運作的核心任務競争共享資源。

       事實上,自旋鎖的初衷就是:在短期間内進行輕量級的鎖定。一個被占用的自旋鎖使得請求它的線程在等待鎖重新可用的期間進行自旋(特别浪費處理器時間),是以自旋鎖不應該被持有時間過長。如果需要長時間鎖定的話, 最好使用信号量。自旋鎖的基本形式如下:

spin_lock(&mr_lock);

//臨界區

spin_unlock(&mr_lock);

        因為自旋鎖在同一時刻隻能被最多一個核心任務持有,是以一個時刻隻有一個線程允許存在于臨界區中。這點很好地滿足了對稱多處理機器需要的鎖定服務。在單處理器上,自旋鎖僅僅當作一個設定核心搶占的開關。如果核心搶占也不存在,那麼自旋鎖會在編譯時被完全剔除出核心。執行個體:在一線背光調節時,由于脈沖變化時間過短,要保證控制脈沖的延時不被其他操作所中斷或者拖延,使用自旋鎖可起到作用。

DEFINE_SPINLOCK(g_handle_bk_lock);
unsigned long g_handle_bk_flag;
......
spin_lock_irqsave(&g_handle_bk_lock, g_handle_bk_flag);
.....//需要保護的操作
spin_unlock_irqrestore(&g_handle_bk_lock, g_handle_bk_flag);          

(3)信号量

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

      信号量的睡眠特性,使得信号量适用于鎖會被長時間持有的情況;隻能在程序上下文中使用,因為中斷上下文中是不能被排程的;另外當代碼持有信号量時,不可以再持有自旋鎖。信号量基本使用形式為:

static DEFINE_MUTEX(accdet_eint_irq_sync_mutex);

mutex_lock(&accdet_eint_irq_sync_mutex);
.............................
mutex_unlock(&accdet_eint_irq_sync_mutex);      

(4)信号量和自旋鎖差別

     雖然聽起來兩者之間的使用條件複雜,其實在實際使用中信号量和自旋鎖并不易混淆。注意以下原則:如果代碼需要睡眠——這往往是發生在和使用者空間同步時——使用信号量是唯一的選擇。如果需要在自旋鎖和信号量中作選擇,應該取決于鎖被持有的時間長短。理想情況是所有的鎖都應該盡可能短的被持有,但是如果鎖的持有時間較長的話,使用信号量是更好的選擇。另外,信号量不同于自旋鎖,它不會關閉核心搶占,是以持有信号量的代碼可以被搶占。這意味者信号量不會對影響排程反應時間帶來負面影響。

繼續閱讀