linux 自旋鎖


一、概述:

自旋鎖是SMP架構中的一種low-level的同步機制。
當線程A想要獲取一把自旋鎖而該鎖又被其它線程鎖持有時,線程A會在一個循環中自旋以檢測鎖是不是已經可用了。對於自選鎖需要注意:

  • 由於自旋時不釋放CPU,因而持有自旋鎖的線程應該盡快釋放自旋鎖,否則等待該自旋鎖的線程會一直在那里自旋,這就會浪費CPU時間。
  • 持有自旋鎖的線程在sleep之前應該釋放自旋鎖以便其它線程可以獲得自旋鎖。

使用任何鎖需要消耗系統資源(內存資源和CPU時間),這種資源消耗可以分為兩類:

  • 建立鎖所需要的資源
  • 線程被阻塞時鎖所需要的資源

spin lock 鎖相關的API:

1 int pthread_spin_destroy(pthread_spinlock_t *);
2 int pthread_spin_init(pthread_spinlock_t *, int);
3 int pthread_spin_lock(pthread_spinlock_t *);
4 int pthread_spin_trylock(pthread_spinlock_t *);
5 int pthread_spin_unlock(pthread_spinlock_t *);

1)初始化自旋鎖

  pthread_spin_init用來申請使用自旋鎖所需要的資源並且將它初始化為非鎖定狀態。pshared的取值及其含義:

  • PTHREAD_PROCESS_SHARED:該自旋鎖可以在多個進程中的線程之間共享。
  • PTHREAD_PROCESS_PRIVATE: 僅初始化本自旋鎖的線程所在的進程內的線程才能夠使用該自旋鎖。

2)獲得一個自旋鎖

  pthread_spin_lock用來獲取(鎖定)指定的自旋鎖. 如果該自旋鎖當前沒有被其它線程所持有,則調用該函數的線程獲得該自旋鎖.否則該函數在獲得自旋鎖之前不會返回。如果調用該函數的線程在調用該函數時已經持有了該自旋鎖,則結果是不確定的。

3)嘗試獲取一個自旋鎖

  pthread_spin_trylock會嘗試獲取指定的自旋鎖,如果無法獲取則理解返回失敗。

4)釋放(解鎖)一個自旋鎖

  pthread_spin_unlock用於釋放指定的自旋鎖。

5)銷毀一個自旋鎖

 pthread_spin_destroy用來銷毀指定的自旋鎖並釋放所有相關聯的資源(所謂的所有指的是由pthread_spin_init自動申請的資源)在調用該函數之后如果沒有調用pthread_spin_init重新初始化自旋鎖,則任何嘗試使用該鎖的調用的結果都是未定義的。如果調用該

函數時自旋鎖正在被使用或者自旋鎖未被初始化則結果是未定義的。

Pthreads提供的Mutex鎖操作相關的API主要有:

1 pthread_mutex_lock (pthread_mutex_t *mutex);
2 pthread_mutex_trylock (pthread_mutex_t *mutex);
3 pthread_mutex_unlock (pthread_mutex_t *mutex);
Pthreads提供的與Spin Lock鎖操作相關的API主要有:
pthread_spin_lock (pthread_spinlock_t *lock);
pthread_spin_trylock (pthread_spinlock_t *lock);
pthread_spin_unlock (pthread_spinlock_t *lock);

   從實現原理上來講,Mutex屬於sleep-waiting類型的鎖。例如在一個雙核的機器上有兩個線程(線程A和線程B),它們分別運行在Core0和Core1上。假設線程A想要通過pthread_mutex_lock操作去得到一個臨界區的鎖,而此時這個鎖正被線程B所持有,那么線

程A就會被阻塞(blocking),Core0 會在此時進行上下文切換(Context Switch)將線程A置於等待隊列中,此時Core0就可以運行其他的任務(例如另一個線程C)而不必進行忙等待。而Spin lock則不然,它屬於busy-waiting類型的鎖,如果線程A是使用

pthread_spin_lock操作去請求鎖,那么線程A就會一直在 Core0上進行忙等待並不停的進行鎖請求,直到得到這個鎖為止

   如果大家去查閱Linux glibc中對pthreads API的實現NPTL(Native POSIX Thread Library) 的源碼的話(使用”getconf GNU_LIBPTHREAD_VERSION”命令可以得到我們系統中NPTL的版本號),就會發現pthread_mutex_lock()操作如果沒有鎖成功的話就會

調用system_wait()的系統調用並將當前線程加入該mutex的等待隊列里。而spin lock則可以理解為在一個while(1)循環中用內嵌的匯編代碼實現的鎖操作(印象中看過一篇論文介紹說在linux內核中spin lock操作只需要兩條CPU指令,解鎖操作只用一條指令就可以完

成)。有興趣的朋友可以參考另一個名為sanos的微內核中pthreds API的實現:mutex.c spinlock.c,盡管與NPTL中的代碼實現不盡相同,但是因為它的實現非常簡單易懂,對我們理解spin lock和mutex的特性還是很有幫助的。

        對於自旋鎖來說,它只需要消耗很少的資源來建立鎖;隨后當線程被阻塞時,它就會一直重復檢查看鎖是否可用了,也就是說當自旋鎖處於等待狀態時它會一直消耗CPU時間。

        對於互斥鎖來說,與自旋鎖相比它需要消耗大量的系統資源來建立鎖;隨后當線程被阻塞時,線程的調度狀態被修改,並且線程被加入等待線程隊列;最后當鎖可用時,在獲取鎖之前,線程會被從等待隊列取出並更改其調度狀態;但是在線程被阻塞期間,它不消耗

CPU資源。

        因此自旋鎖和互斥鎖適用於不同的場景。自旋鎖適用於那些僅需要阻塞很短時間的場景,而互斥鎖適用於那些可能會阻塞很長時間的場景。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM