程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> posix多線程有感--線程高級編程(互斥量屬性)

posix多線程有感--線程高級編程(互斥量屬性)

編輯:C++入門知識

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

[cpp] 
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); 

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.獲得/修改類型互斥量屬性

[cpp] 
int pthread_mutexattr_settype(pthread_mutexattr_t *attr,int kind); 
int pthread_mutexattr_gettype(pthread_mutexattr_t *attr,int *kind); 

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:如果一個線程對這種類型的互斥鎖重復上鎖,不會引起死鎖。一個線程對這類互斥鎖的多次重復上鎖必須由這個線程來重復相同數量的解鎖,這樣才能解開這個互斥鎖,別的線程才能得到這個互斥鎖。如果試圖解鎖一個由別的線程鎖定的互斥鎖將會返回一個錯誤代碼。如果一個線程試圖解鎖已經被解鎖的互斥鎖也將會返回一個錯誤代碼。這種類型的互斥鎖只能是進程私有的(作用域屬性為PTHREAD_PROCESS_PRIVATE)。

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

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

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:此協議值會影響擁有該互斥鎖的線程的優先級和調度。如果更高優先級的線程因thrd1所擁有的一個或多個互斥鎖而被阻塞,而這些互斥鎖是用PTHREAD_PRIO_INHERIT 初始化的,則thrd1的運行優先級為優先級pri1和優先級pri2中優先級較高的那一個,其中 thrd1的優先級為pri1,所有正在等待這些互斥鎖(這些互斥鎖是 thrd1指所擁有的互斥鎖)的線程的最高優先級為pri2,如果thrd1因另一個線程(thrd3) 擁有的互斥鎖而被阻塞,則相同的優先級繼承效應會以遞歸方式傳播給thrd3。使用PTHREAD_PRIO_INHERIT可以避免優先級逆轉。當低優先級的線程持有較高優先級線程所需的鎖時,就會發生優先級逆轉。此時只有在較低優先級的線程釋放該鎖之後,較高優先級的線程才能繼續執行。如果沒有優先級繼承,底優先級的線程可能會在很長一段時間內都得不到調度,而這會導致等待低優先級線程鎖持有的鎖的高優先級線程也等待很長時間(因為低優先級線程無法運行,因而就無法釋放鎖,所以高優先級線程只能繼續阻塞在鎖上)。使用優先級繼承可以短時間的提高低優先級線程的優先級,從而使它可以盡快得到調度,然後釋放鎖。低優先級線程在釋放鎖後就會恢復自己的優先級。
PTHREAD_PRIO_PROTECT:當線程擁有一個或多個使用PTHREAD_PRIO_PROTECT 初始化的互斥鎖時,線程的優先級和調度會受到影響。線程將以優先級pri1和優先級pri2中優先級較高的那一個優先級來運行,其中線程的優先級為pri1,所有被線程持有的鎖的最高優先級為pri2,被該線程所持有的鎖阻塞的高優先級線程對該線程的調度沒有影響。
PTHREAD_PRIO_INHERIT 和 PTHREAD_PRIO_PROTECT 只有在采用實時調度策略SCHED_FIFO 或 SCHED_RR的優先級進程內可用。一個線程可以同時擁有多個混合使用 PTHREAD_PRIO_INHERIT 和 PTHREAD_PRIO_PROTECT協議屬性初始化的互斥鎖。在這種情況下,該線程將以通過其中任一協議獲取的最高優先級執行。pthread_mutexattr_getprotocol可用來獲取互斥鎖屬性對象的協議屬性。


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

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

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.設置/獲取互斥鎖的強健屬性

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

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

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved