POSIX threads(簡稱Pthreads)是在多核平臺(tái)上進(jìn)行并行編程的一套常用的API。線程同步(ThreadSynchronization)是并行編程中非常重要的通訊手段,其中最典型的應(yīng)用就是用Pthreads提供的鎖機(jī)制(lock)來對多個(gè)線程之間共享的臨界區(qū)(CriticalSection)進(jìn)行保護(hù)
Pthreads提供了多種鎖機(jī)制,常見的有:1) Mutex(互斥量):pthread_mutex_lock2) Spin lock(自旋鎖):pthread_spin_lock3) Condition Variable(條件變量):pthread_con_lock4) Read/Write lock(讀寫鎖):pthread_rwlock_lock
1 Pthread mutex
mutex屬于sleep-waiting類型的鎖. 從 2.6.x 系列穩(wěn)定版內(nèi)核開始, linux 的 mutex 都是futex (Fast-Usermode-muTEX)鎖.futex(快速用戶區(qū)互斥的簡稱)是一個(gè)在Linux上實(shí)現(xiàn)鎖定和構(gòu)建高級抽象鎖如信號量和POSIX互斥的基本工具。它們第一次出現(xiàn)在內(nèi)核開發(fā)的2.5.7版;其語義在2.5.40固定下來,然后在2.6.x系列穩(wěn)定版內(nèi)核中出現(xiàn)。
futex 是由用戶空間的一個(gè)對齊的整型變量和附在其上的內(nèi)核空間等待隊(duì)列構(gòu)成. 多進(jìn)程或多線程絕大多數(shù)情況下對位于用戶空間的futex 的整型變量進(jìn)行操作(匯編語言調(diào)用CPU提供的原子操作指令來增加或減少),而其它情況下,則需要通過代價(jià)較大的系統(tǒng)調(diào)用來對位于內(nèi)核空間的等待隊(duì)列進(jìn)行操作(如喚醒等待的進(jìn)程/線程,或 將當(dāng)前進(jìn)程/線程放入等待隊(duì)列). 除了多個(gè)線程同時(shí)競爭鎖的少數(shù)情況外,基于 futex 的 lock 操作是不需要進(jìn)行代價(jià)昂貴的系統(tǒng)調(diào)用操作的。這種機(jī)制的核心思想是通過將大多數(shù)情況下非同時(shí)競爭 lock 的操作放到在用戶空間來執(zhí)行,而不是代價(jià)昂貴的內(nèi)核系統(tǒng)調(diào)用方式來執(zhí)行,從而提高了效率.
Pthreads提供的Mutex鎖操作相關(guān)的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 spinlockspinlock,也稱自旋鎖,是屬于busy-waiting類型的鎖.在多處理器環(huán)境中, 自旋鎖最多只能被一個(gè)可執(zhí)行線程持有。如果一個(gè)可執(zhí)行線程試圖獲得一個(gè)被爭用(已經(jīng)被持有的)自旋鎖,那么該線程就會(huì)一直進(jìn)行忙等待,自旋,也就是空轉(zhuǎn),等待鎖重新可用。如果鎖未被爭用,請求鎖的執(zhí)行線程便立刻得到它,繼續(xù)執(zhí)行。
一個(gè)被爭用的自旋鎖使得請求它的線程在等待鎖重新可用時(shí)自旋,特別的浪費(fèi)CPU時(shí)間,所以自旋鎖不應(yīng)該被長時(shí)間的持有。實(shí)際上,這就是自旋鎖的設(shè)計(jì)初衷,在短時(shí)間內(nèi)進(jìn)行輕量級加鎖。
Kernel中的自旋鎖不能夠在能夠?qū)е滤叩沫h(huán)境中使用。舉個(gè)例子,一個(gè)線程A獲得了自旋鎖L;這個(gè)時(shí)候,發(fā)生了中斷,在對應(yīng)的中斷處理函數(shù)B中,也嘗試獲得自旋鎖L,就會(huì)中斷處理程序進(jìn)行自旋。但是原先鎖的持有者只有在中斷處理程序結(jié)束后,采用機(jī)會(huì)釋放自旋鎖,從而導(dǎo)致死鎖。 由于涉及到多個(gè)處理器環(huán)境下,spin lock的效率非常重要。因?yàn)樵诘却齭pin lock的過程,處理器只是不停的循環(huán)檢查,并不執(zhí)行其他指令。但即使這樣, 一般來說,spinlock的開銷還是比進(jìn)程調(diào)度(context switch)少得多。這就是spin lock 被廣泛應(yīng)用在多處理器環(huán)境的原因
Pthreads提供的與Spin Lock鎖操作相關(guān)的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是利用線程間共享的全局變量進(jìn)行同步的一種機(jī)制。條件變量上的基本操作有:觸發(fā)條件(當(dāng)條件變?yōu)?true 時(shí));等待條件,掛起線程直到其他線程觸發(fā)條件。
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(前者為動(dòng)態(tài)初始化,后者為靜態(tài)初始化);屬性置為NULL(2)等待條件成立.pthread_wait,pthread_timewait.wait()釋放鎖,并阻塞等待條件變量為真,timewait()設(shè)置等待時(shí)間,仍未signal,返回ETIMEOUT(加鎖保證只有一個(gè)線程wait)(3)激活條件變量:pthread_cond_signal,pthread_cond_broadcast(激活所有等待線程)(4)清除條件變量:destroy;無線程等待,否則返回EBUSY
4 Pthread總結(jié)
從實(shí)現(xiàn)原理上來講,Mutex屬于sleep-waiting類型的鎖。例如在一個(gè)雙核的機(jī)器上有兩個(gè)線程(線程A和線程B),它們分別運(yùn)行在Core0和Core1上。假設(shè)線程A想要通過pthread_mutex_lock操作去得到一個(gè)臨界區(qū)的鎖,而此時(shí)這個(gè)鎖正被線程B所持有,那么線程A就會(huì)被阻塞(blocking),Core0 會(huì)在此時(shí)進(jìn)行上下文切換(Context Switch)將線程A置于等待隊(duì)列中,此時(shí)Core0就可以運(yùn)行其他的任務(wù)(例如另一個(gè)線程C)而不必進(jìn)行忙等待。而Spin lock則不然,它屬于busy-waiting類型的鎖,如果線程A是使用pthread_spin_lock操作去請求鎖,那么線程A就會(huì)一直在 Core0上進(jìn)行忙等待并不停的進(jìn)行鎖請求,直到得到這個(gè)鎖為止。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注