歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Unix知識 >> Unix基礎知識

UNIX環境高級編程:互斥量屬性

互斥量具有一些屬性,通過修改這些屬性可以控制鎖的一些行為。缺省的互斥鎖屬性及其值如下:

pshared:         PTHREAD_PROCESS_PRIVATE

type:                 PTHREAD_MUTEX_DEFAULT

protocol:          PTHREAD_PRIO_NONE

prioceiling:       –

robustness:    PTHREAD_MUTEX_STALLED_NP

1.獲得/修改共享互斥量屬性

pthread_mutexattr_t attr;  
int pthread_mutexattr_init(pthread_mutexattr_t *attr);  
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);  
int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr,int *pshared);  
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,int pshared);

參數:pshared的取值可以是: PTHREAD_PROCESS_SHARED,PTHREAD_PROCESS_PRIVATE

說明:如果互斥鎖屬性對象的pshared屬性被置PTHREAD_PROCESS_SHARED。那麼由這個屬性對象創建的互斥鎖將被保存在共享內存中,可以被多個進程中的線程共享。如pshared屬性被置為PTHREAD_PROCESS_PRIVATE,那麼只有和創建這個互斥鎖的線程在同一個進程中的線程才能訪問這個互斥鎖。

2.獲得/修改類型互斥量屬性

int pthread_mutexattr_settype(pthread_mutexattr_t *attr,int kind);  
int pthread_mutexattr_gettype(pthread_mutexattr_t *attr,int *kind);

PTHREAD_MUTEX_DEFAULT(缺省的互斥鎖類型屬性):這種類型的互斥鎖不會自動檢測死鎖。如果一個線程試圖對一個互斥鎖重復鎖定,將會引起不可預料的結果。如果試圖解鎖一個由別的線程鎖定的互斥鎖會引發不可預料的結果。如果一個線程試圖解鎖已經被解鎖的互斥鎖也會引發不可預料的結果。POSIX標准規定,對於某一具體的實現,可以把這種類型的互斥鎖定義為其他類型的互斥鎖。

PTHREAD_MUTEX_NORMAL:這種類型的互斥鎖不會自動檢測死鎖。如果一個線程試圖對一個互斥鎖重復鎖定,將會引起這個線程的死鎖。如果試圖解鎖一個由別的線程鎖定的互斥鎖會引發不可預料的結果。如果一個線程試圖解鎖已經被解鎖的互斥鎖也會引發不可預料的結果。

PTHREAD_MUTEX_ERRORCHECK:這種類型的互斥鎖會自動檢測死鎖。 如果一個線程試圖對一個互斥鎖重復鎖定,將會返回一個錯誤代碼。 如果試圖解鎖一個由別的線程鎖定的互斥鎖將會返回一個錯誤代碼。如果一個線程試圖解鎖已經被解鎖的互斥鎖也將會返回一個錯誤代碼。

PTHREAD_MUTEX_RECURSIVE:如果一個線程對這種類型的互斥鎖重復上鎖,不會引起死鎖。一個線程對這類互斥鎖的多次重復上鎖必須由這個線程來重復相同數量的解鎖,這樣才能解開這個互斥鎖,別的線程才能得到這個互斥鎖。如果試圖解鎖一個由別的線程鎖定的互斥鎖將會返回一個錯誤代碼。

3.設置/獲取互斥鎖的協議屬性

int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol);  
int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, int *protocol);

互斥鎖協議屬性的可能值及其含義:

PTHREAD_PRIO_NONE:線程的優先級和調度不會受到互斥鎖擁有權的影響。

PTHREAD_PRIO_INHERIT:當高優先級的等待低優先級的線程鎖定互斥量時,低優先級的線程以高優先級線程的優先級運行。這種方式將以繼承的形式傳遞。當線程解鎖互斥量時,線程的優先級自動被將到它原來的優先級。(“優先級繼承”意味著,當一個線程在由另一個低優先級線程擁有的互斥量上等待時,後者的優先級將被增加到等待線程的優先級.)

PTHREAD_PRIO_PROTECT:擁有該類型的互斥量的線程將以自己的優先級和它擁有的互斥量的線程將以自己的優先級和它擁有的互斥量的優先級較高者運行,其他等待該線程擁有的鎖得線程對該線程的調度優先級沒有影響。

注意:PTHREAD_PRIO_INHERIT 和 PTHREAD_PRIO_PROTECT 只有在采用實時調度策略SCHED_FIFO 或SCHED_RR的優先級進程內可用。

一個線程可以同時擁有多個混合使用PTHREAD_PRIO_INHERIT 和PTHREAD_PRIO_PROTECT協議屬性初始化的互斥鎖。在這種情況下,該線程將以通過其中任一協議獲取的最高優先級執行。pthread_mutexattr_getprotocol可用來獲取互斥鎖屬性對象的協議屬性。

查看本欄目更多精彩內容:http://www.bianceng.cn/OS/unix/

4.設置/獲取互斥鎖屬性對象的優先級上限屬性

int pthread_mutexattr_setprioceiling(pthread_mutexatt_t *attr, int prioceiling, int *oldceiling);  
int pthread_mutexattr_getprioceiling(const pthread_mutexatt_t *attr, int *prioceiling);

prioceiling指定已初始化互斥鎖的優先級上限。優先級上限定義執行互斥鎖保護的臨界段時的最低優先級。prioceiling 位於SCHED_FIFO 所定義的優先級的最大范圍內。要避免優先級倒置,請將prioceiling 設置為高於或等於可能會鎖定特定互斥鎖的所有線程的最高優先級。oldceiling 用於返回以前的優先級上限值。

pthread_mutex_setprioceiling可更改互斥鎖mutex的優先級上限prioceiling。

pthread_mutex_setprioceiling可鎖定互斥鎖(如果未鎖定的話),或者一直處於阻塞狀態,直到它成功鎖定該互斥鎖,更改該互斥鎖的優先級上限並將該互斥鎖釋放為止。鎖定互斥鎖的過程無需遵循優先級保護協議。

如果 pthread_mutex_setprioceiling成功,則將在 old_ceiling 中返回以前的優先級上限值。如果pthread_mutex_setprioceiling失敗,則互斥鎖的優先級上限保持不變。pthread_mutex_getprioceiling會返回mutex 的優先級上限prioceiling。

注意:“優先級上限”協議意味著當一個線程擁有互斥量時,它將以指定的優先級運行。

5.設置/獲取互斥鎖的強健屬性

int pthread_mutexattr_setrobust_np(pthread_mutexattr_t *attr, int *robustness);  
int pthread_mutexattr_getrobust_np(const pthread_mutexattr_t *attr, int *robustness);

robustness 定義在互斥鎖的持有者“死亡”時的行為。pthread.h 中定義的robustness 的值為PTHREAD_MUTEX_ROBUST_NP 或 PTHREAD_MUTEX_STALLED_NP。缺省值為PTHREAD_MUTEX_STALLED_NP。

PTHREAD_MUTEX_STALLED_NP: 如果互斥鎖的持有者死亡,則以後對pthread_mutex_lock() 的所有調用將以不確定的方式被阻塞。

PTHREAD_MUTEX_ROBUST_NP: 如果互斥鎖的持有者“死亡”了,或者持有這樣的互斥鎖的進程unmap了互斥鎖所在的共享內存或者持有這樣的互斥鎖的進程執行了exec調用,則會解除鎖定該互斥鎖。互斥鎖的下一個持有者將獲取該互斥鎖,並返回錯誤EOWNWERDEAD。

如果互斥鎖具有PTHREAD_MUTEX_ROBUST_NP的屬性,則應用程序在獲取該鎖時必須檢查pthread_mutex_lock 的返回代碼看獲取鎖時是否返回了EOWNWERDEAD錯誤。如果是,則

互斥鎖的新的持有者應使該互斥鎖所保護的狀態保持一致。因為互斥鎖的上一個持有者“死亡”時互斥鎖所保護的狀態可能出於不一致的狀態。

如果互斥鎖的新的持有者能夠使該狀態保持一致,請針對該互斥鎖調用pthread_mutex_consistent_np(),並解除鎖定該互斥鎖。

如果互斥鎖的新的持有者無法使該狀態保持一致,請勿針對該互斥鎖調用pthread_mutex_consistent_np(),而是解除鎖定該互斥鎖。所有等待的線程都將被喚醒,以後對pthread_mutex_lock() 的所有調用都將無法獲取該互斥鎖。返回錯誤為ENOTRECOVERABLE。

如果一個線程獲取了互斥鎖,但是獲取時得到了EOWNERDEAD的錯誤,然後它終止並且沒有釋放互斥鎖 ,則下一個持有者獲取該鎖時將返回代碼EOWNERDEAD。

注意:

1、互斥量需要時間來加鎖和解鎖。鎖住較少互斥量的程序通常運行得更快。所以,互斥量應該盡量少,夠用即可,每個互斥量保護的區域應則盡量大。

2、互斥量的本質是串行執行。如果很多線程需要頻繁地加鎖同一個互斥量,則線程的大部分時間就會在等待,這對性能是有害的。如果互斥量保護的數據(或代碼)包含彼此無關的片段,則可以特大的互斥量分解為幾個小的互斥量來提高性能。這樣,任意時刻需要小互斥量的線程減少,線程等待時間就會減少。所以,互斥量應該足夠多(到有意義的地步),每個互斥量保護的區域則應盡量的少。

3、POSIX線程鎖機制的Linux實現都不是取消點,因此,延遲取消類型的線程不會因收到取消信號而離開加鎖等待。

4、線程在加鎖後解鎖前被取消,鎖將永遠保持鎖定狀態。因此如果在關鍵區段內有取消點存在,或者設置了異步取消類型,則必須在退出回調函數中解鎖。

5、鎖機制不是異步信號安全的,也就是說,不應該在信號處理過程中使用互斥鎖,否則容易造成死鎖。

Copyright © Linux教程網 All Rights Reserved