Pthread鎖機制

        POSIX threads(簡稱Pthreads)是在多核平臺上進行並行編程的一套常用的API。線程同步(ThreadSynchronization)是並行編程中非常重要的通訊手段,其中最典型的應用就是用Pthreads提供的鎖機制(lock)來對多個線程之間共享的臨界區(CriticalSection)進行保護

Pthreads提供了多種鎖機制,常見的有:
1) Mutex(互斥量):pthread_mutex_lock
2) Spin lock(自旋鎖):pthread_spin_lock
3) Condition Variable(條件變量):pthread_con_lock
4) Read/Write lock(讀寫鎖):pthread_rwlock_lock

1 Pthread mutex

    mutex屬於sleep-waiting類型的鎖. 從 2.6.x 系列穩定版內核開始, Linux 的 mutex 都是futex (Fast-Usermode-muTEX)鎖.
futex(快速用戶區互斥的簡稱)是一個在Linux上實現鎖定和構建高級抽象鎖如信號量和POSIX互斥的基本工具。它們第一次出現在內核開發的2.5.7版;其語義在2.5.40固定下來,然後在2.6.x系列穩定版內核中出現。

    futex 是由用戶空間的一個對齊的整型變量和附在其上的內核空間等待隊列構成. 多進程或多線程絕大多數情況下對位於用戶空間的futex 的整型變量進行操作(彙編語言調用CPU提供的原子操作指令來增加或減少),而其它情況下,則需要通過代價較大的系統調用來對位於內核空間的等待隊列進行操作(如喚醒等待的進程/線程,或 將當前進程/線程放入等待隊列). 除了多個線程同時競爭鎖的少數情況外,基於 futex 的 lock 操作是不需要進行代價昂貴的系統調用操作的。這種機制的核心思想是通過將大多數情況下非同時競爭 lock 的操作放到在用戶空間來執行,而不是代價昂貴的內核系統調用方式來執行,從而提高了效率.

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);

2 Pthread spinlock

    spinlock,也稱自旋鎖,是屬於busy-waiting類型的鎖.在多處理器環境中, 自旋鎖最多隻能被一個可執行線程持有。如果一個可執行線程試圖獲得一個被爭用(已經被持有的)自旋鎖,那麼該線程就會一直進行忙等待,自旋,也就是空轉,等待鎖重新可用。如果鎖未被爭用,請求鎖的執行線程便立刻得到它,繼續執行。

    一個被爭用的自旋鎖使得請求它的線程在等待鎖重新可用時自旋,特別的浪費CPU時間,所以自旋鎖不應該被長時間的持有。實際上,這就是自旋鎖的設計初衷,在短時間內進行輕量級加鎖。

    Kernel中的自旋鎖不能夠在能夠導致睡眠的環境中使用。舉個例子,一個線程A獲得了自旋鎖L;這個時候,發生了中斷,在對應的中斷處理函數B中,也嘗試獲得自旋鎖L,就會中斷處理程序進行自旋。但是原先鎖的持有者只有在中斷處理程序結束後,採用機會釋放自旋鎖,從而導致死鎖。
    由於涉及到多個處理器環境下,spin lock的效率非常重要。因爲在等待spin lock的過程,處理器只是不停的循環檢查,並不執行其他指令。但即使這樣, 一般來說,spinlock的開銷還是比進程調度(context switch)少得多。這就是spin lock 被廣泛應用在多處理器環境的原因

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);

3 Pthread condition

    condition是利用線程間共享的全局變量進行同步的一種機制。條件變量上的基本操作有:觸發條件(當條件變爲 true 時);等待條件,掛起線程直到其他線程觸發條件。

int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr);   
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime);
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);  //解除所有線程的阻塞

(1)初始化.init()或者pthread_cond_t cond=PTHREAD_COND_INITIALIER(前者爲動態初始化,後者爲靜態初始化);屬性置爲NULL
(2)等待條件成立.pthread_wait,pthread_timewait.wait()釋放鎖,並阻塞等待條件變量爲真,timewait()設置等待時間,仍未signal,返回ETIMEOUT(加鎖保證只有一個線程wait)
(3)激活條件變量:pthread_cond_signal,pthread_cond_broadcast(激活所有等待線程)
(4)清除條件變量:destroy;無線程等待,否則返回EBUSY

4 Pthread總結

   從實現原理上來講,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上進行忙等待並不停的進行鎖請求,直到得到這個鎖爲止。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章