在過程管理中,互斥變量和條件變量是必不可少的,任務(wù)間的調(diào)度幾乎是由互斥變量和條件變量控制的,互斥體的實現(xiàn)類似于進(jìn)程信號量的實現(xiàn),本文是武林技術(shù)頻道小編為大家整理的解析互斥量與條件變量的詳解,一起來看看吧!
一、互斥量
1. 初始化與銷毀:
???對于靜態(tài)分配的互斥量, 可以初始化為PTHREAD_MUTEX_INITIALIZER(等價于pthread_mutex_init(…, NULL))或調(diào)用pthread_mutex_init。
???對于動態(tài)分配的互斥量, 在申請內(nèi)存(malloc)之后,通過pthread_mutex_init進(jìn)行初始化, 并且在釋放內(nèi)存(free)前需要調(diào)用pthread_mutex_destroy.
? ? int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t*restric attr);
? ? int pthread_mutex_destroy(pthread_mutex_t *mutex);
返回值:成功則返回0,出錯則返回錯誤編號.
說明:1、如果使用默認(rèn)的屬性初始化互斥量,只需把a(bǔ)ttr設(shè)為NULL。
? ? ? ? ? ?2、銷毀一個互斥鎖即意味著釋放它所占用的資源,且要求鎖當(dāng)前處于開放狀態(tài)。由于在Linux中,互斥鎖并不占用任何資源,因此 LinuxThreads中的pthread_mutex_destroy()除了檢查鎖狀態(tài)以外(鎖定狀態(tài)則返回EBUSY)沒有其他動作。
2. 互斥操作:
???對共享資源的訪問, 要對互斥量進(jìn)行加鎖,如果互斥量已經(jīng)上了鎖, 調(diào)用線程會阻塞,直到互斥量被解鎖。在完成了對共享資源的訪問后, 要對互斥量進(jìn)行解鎖。
? ??int pthread_mutex_lock(pthread_mutex_t *mutex);? //P操作:請求資源(+1)
? ??int pthread_mutex_trylock(pthread_mutex_t *mutex);
? ??int pthread_mutex_unlock(pthread_mutex_t *mutex);//V操作:釋放資源(-1)
返回值:成功則返回0,出錯則返回錯誤編號.
說明:1、想給一個互斥量上鎖,我們調(diào)用pthread_mutex_lock。如果mutex已經(jīng)上鎖,調(diào)用的線程將會被阻塞,直至信號量解鎖。
???????2、具體說一下trylock函數(shù), 這個函數(shù)是非阻塞調(diào)用模式,也就是說, 如果互斥量沒被鎖住,trylock函數(shù)將把互斥量加鎖, 并獲得對共享資源的訪問權(quán)限;如果互斥量被鎖住了,trylock函數(shù)將不會阻塞等待而直接返回EBUSY, 表示共享資源處于忙狀態(tài)。
???????3、要解鎖一個信號量,我們調(diào)用phtread_mutex_unlock。
3. 死鎖、同步、與互斥的關(guān)系
3.1 死鎖:
???有時,可能需要同時訪問兩個資源。您可能正在使用其中的一個資源,隨后發(fā)現(xiàn)還需要另一個資源。如果兩個線程嘗試聲明這兩個資源,但是以不同的順序鎖定與這些資源相關(guān)聯(lián)的互斥鎖,則會出現(xiàn)問題。例如,如果兩個線程分別鎖定互斥鎖1 和互斥鎖 2,則每個線程嘗試鎖定另一個互斥鎖時,將會出現(xiàn)死鎖。下面的例子說明了可能的死鎖情況。
?
線程 1 | 線程 2 |
pthread_mutex_lock(&m1); pthread_mutex_lock(&m2); do something…… pthread_mutex_unlock(&m2); pthread_mutex_unlock(&m1); | pthread_mutex_lock(&m2); pthread_mutex_lock(&m1); do something…… pthread_mutex_unlock(&m1); pthread_mutex_unlock(&m2); |
3.2 同步:??
?
線程 1 | 線程 2 |
pthread_mutex_lock(&m1); do something…… pthread_mutex_unlock(&m2); | pthread_mutex_lock(&m2); do something…… pthread_mutex_unlock(&m1); |
3.3 互斥:?
?
線程 1 |
pthread_mutex_lock(&m1); do something……//臨界區(qū)(Critical Section) pthread_mutex_unlock(&m1); |
?
4. 互斥量之前輩總結(jié)
? ? ? ?1.對共享資源操作前一定要獲得鎖。
? ? ? ?2.完成操作以后一定要釋放鎖。
? ? ? ?3.盡量短時間地占用鎖。
? ? ? ?4.如果有多鎖, 如獲得順序是ABC連環(huán)扣,釋放順序也應(yīng)該是ABC。
? ? ? ?5.線程錯誤返回時應(yīng)該釋放它所獲得的鎖。
二、條件變量
1. 創(chuàng)建和注銷
??? 條件變量和互斥鎖一樣,都有靜態(tài)動態(tài)兩種創(chuàng)建方式
a.?靜態(tài)方式
??? 靜態(tài)方式使用PTHREAD_COND_INITIALIZER常量,如:?pthread_cond_t ?cond = PTHREAD_COND_INITIALIZER
b.?動態(tài)方式
???int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr)
??? 使用 cond_attr 指定的屬性初始化條件變量 cond,當(dāng) cond_attr為 NULL時,使用缺省的屬性。LinuxThreads實現(xiàn)條件變量不支持屬性,因此 cond_attr參數(shù)實際被忽略。
c.?注銷
??? int pthread_cond_destroy(pthread_cond_t *cond)
? ??注銷一個條件變量需要調(diào)用pthread_cond_destroy(),只有在沒有線程在該條件變量上等待的時候才能注銷這個條件變量,否則返回EBUSY。因為Linux實現(xiàn)的條件變量沒有分配什么資源,所以注銷動作只包括檢查是否有等待線程。
2. 等待和激發(fā)
2.1?等待
???int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
? ?這個函數(shù)是POSIX線程信號發(fā)送系統(tǒng)的核心,也是最難以理解的部分,過程為:解鎖-wait-收到信號-加鎖-返回。
2.2?設(shè)置時間的等待
???int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, conststruct timespec *abstime)
??? pthread_cond_timedwait和 pthread_cond_wait一樣,自動解鎖互斥量及等待條件變量,但它還限定了等待時間。如果在 abstime指定的時間內(nèi) cond未觸發(fā),互斥量 mutex被重新加鎖,并返回錯誤 ETIMEDOUT。abstime參數(shù)指定一個絕對時間,時間原點與 time和 gettimeofday相同:abstime = 0表示 1970 年 1月 1 日 00:00:00 GMT。?
2.3?激發(fā)
??? int pthread_cond_signal(pthread_cond_t *cond);
??? int pthread_cond_broadcast(pthread_cond_t *cond);
??? 激發(fā)條件有兩種形式,pthread_cond_signal()激活一個等待該條件的線程,多個線程阻塞在此條件變量上時,哪一個線程被喚醒是由線程的調(diào)度策略所決定的;而pthread_cond_broadcast()則激活所有等待線程,這些線程被喚醒后將再次競爭相應(yīng)的互斥鎖。
???要注意的是,必須用保護(hù)條件變量的互斥鎖來保護(hù)激活函數(shù),否則條件滿足信號有可能在測試條件和調(diào)用pthread_cond_wait()函數(shù)之間被發(fā)出,從而造成無限制的等待。?
三、互斥量與條件變量
? ??互斥量存在的問題:從本質(zhì)上說互斥量就是一把鎖,互斥量串行執(zhí)行,能確保每次只有一個線程訪問。互斥量是線程程序必需的工具,但它們并非萬能的。例如,如果線程正在輪詢等待共享數(shù)據(jù)內(nèi)某個條件出現(xiàn),那會發(fā)生什么呢?它可以重復(fù)對互斥對象鎖定和解鎖,每次都會檢查共享數(shù)據(jù)結(jié)構(gòu),以查找某個值。但這是在浪費時間和資源,而且這種繁忙查詢的效率非常低。同樣,在每次檢查之間讓線程短暫地進(jìn)入睡眠,比如睡眠3s,但是因此線程代碼就無法最快作出響應(yīng)。
? ??問題的解決:?條件變量通過允許線程阻塞和等待另一個線程發(fā)送信號的方法彌補(bǔ)了互斥鎖的不足,條件變量常和互斥鎖一起使用。使用時,條件變量被用來阻塞一個線程,當(dāng)條件不滿足時,線程往往解開相應(yīng)的互斥鎖并等待條件發(fā)生變化。一旦其它的某個線程改變了條件變量,它將通知相應(yīng)的條件變量喚醒一個或多個正被此條件變量阻塞的線程。這些線程將重新鎖定互斥鎖并重新測試條件是否滿足。
四、線程管理相關(guān)代碼
以上就是關(guān)于解析互斥量與條件變量的詳解,介紹的很詳細(xì)了,如果你還想了解更多的知識,請隨時來武林技術(shù)頻道學(xué)習(xí)吧!
?
|
新聞熱點
疑難解答
圖片精選