posix多執行緒有感 自旋鎖

2021-09-10 19:03:52 字數 3101 閱讀 9515

**:

自旋鎖是smp架構中的一種low-level的同步機制。

當執行緒a想要獲取一把自旋鎖而該鎖又被其它執行緒鎖持有時,執行緒a會在乙個迴圈中自旋以檢測鎖是不是已經可用了。對於自選鎖需要注意:

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

建立鎖所需要的資源

當執行緒被阻塞時鎖所需要的資源

int pthread_spin_destroy(pthread_spinlock_t *);

int pthread_spin_init(pthread_spinlock_t *, int);

int pthread_spin_lock(pthread_spinlock_t *);

int pthread_spin_trylock(pthread_spinlock_t *);

int pthread_spin_unlock(pthread_spinlock_t *);

1)初始化自旋鎖

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

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

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

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

pthread_mutex_lock (pthread_mutex_t *mutex);

pthread_mutex_trylock (pthread_mutex_t *mutex);

pthread_mutex_unlock (pthread_mutex_t *mutex);

pthread_spin_lock (pthread_spinlock_t *lock);

pthread_spin_trylock (pthread_spinlock_t *lock);

pthread_spin_unlock (pthread_spinlock_t *lock);

自旋鎖與linux核心程序排程關係

如果臨界區可能包含引起睡眠的**則不能使用自旋鎖,否則可能引起死鎖。

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

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

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 while (0)

注意到「preempt_disable()」,這個呼叫的功能是「關搶占」(在spin_unlock中會重新開啟搶占功能)。從 中可以看出,使用自旋鎖保護的區域是工作在非搶占的狀態;即使獲取不到鎖,在「自旋」狀態也是禁止搶占的。了解到這,我想咱們應該能夠理解為何自旋鎖保護 的**不能睡眠了。試想一下,如果在自旋鎖保護的**中間睡眠,此時發生程序排程,則可能另外乙個程序會再次呼叫spinlock保護的這段**。而我們 現在知道了即使在獲取不到鎖的「自旋」狀態,也是禁止搶占的,而「自旋」又是動態的,不會再睡眠了,也就是說在這個處理器上不會再有程序排程發生了,那麼 死鎖自然就發生了。

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

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

● 單處理器搶占核心下:自旋鎖僅僅當作乙個設定核心搶占的開關;

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

linux搶占發生的時間

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

使用者搶占在以下情況下產生:

● 從系統呼叫返回使用者空間

● 從中斷處理程式返回使用者空間

核心搶占會發生在:

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

● 當核心**再一次具有可搶占性的時候。(如:spin_unlock時)

● 如果核心中的任務顯式的呼叫schedule()

● 如果核心中的任務阻塞。

基本的程序排程就是發生在時鐘中斷後,並且發現程序的時間片已經使用完了,則發生程序搶占。通常我們會利用中斷處理程式返回核心空間的時候可以進行內 核搶占這個特性來提高一些i/o操作的實時性,如:當i/o事件發生的是時候,對應的中斷處理程式被啟用,當它發現有程序在等待這個i/o事件的時候,它 會啟用等待程序,並且設定當前正在執行程序的need_resched標誌,這樣在中斷處理程式返回的時候,排程程式被啟用,原來在等待i/o事件的程序 (很可能)獲得執行權,從而保證了對i/o事件的相對快速響應(毫秒級)。可以看出,在i/o事件發生的時候,i/o事件的處理程序會搶占當前程序,系統 的響應速度與排程時間片的長度無關。

總結:

(1)mutex適合對鎖操作非常頻繁的場景,並且具有更好的適應性。儘管相比spin lock它會花費更多的開銷(主要是上下文切換),但是它能適合實際開發中複雜的應用場景,在保證一定效能的前提下提供更大的靈活度。

(2)spin lock的lock/unlock效能更好(花費更少的cpu指令),但是它只適應用於臨界區執行時間很短的場景。而在實際軟體開發中,除非程式設計師對自己 的程式的鎖操作行為非常的了解,否則使用spin lock不是乙個好主意(通常乙個多執行緒程式中對鎖的操作有數以萬次,如果失敗的鎖操作(contended lock requests)過多的話就會浪費很多的時間進行空等待)。

(3)更保險的方法或許是先(保守的)使用 mutex,然後如果對效能還有進一步的需求,可以嘗試使用spin lock進行調優。畢竟我們的程式不像linux kernel那樣對效能需求那麼高(linux kernel最常用的鎖操作是spin lock和rw lock)。

執行緒同步 多執行緒自旋鎖

短時間鎖定的情況下,自旋鎖 spinlock 更快。因為自旋鎖本質上不會讓執行緒休眠,而是一直迴圈嘗試對資源訪問,直到可用。所以自旋鎖線程被阻塞時,不進行執行緒上下文切換,而是空轉等待。對於多核cpu而言,減少了切換執行緒上下文的開銷,從而提高了效能。class program spinlock是n...

linux多執行緒之自旋鎖

基本概念 何謂自旋鎖?它是為實現保護共享資源而提出一種鎖機制。其實,自旋鎖與互斥鎖比較類似,它們都是為了解決對某項資源的互斥使用。無論是互斥鎖,還是自旋鎖,在任何時刻,最多只能有乙個保持者,也就說,在任何時刻最多只能有乙個執行單元獲得鎖。但是兩者在排程機制上略有不同。對於互斥鎖,如果資源已經被占用,...

POSIX執行緒多執行緒例子

include include include include define num threads 6 void thread function void arg int main sleep 1 printf waiting for threads to finish.n for lots of...