互斥量(Mutex)是「mutual exclusion」的縮寫。互斥量是實現線程同步,和保護同時寫共享數據的主要方法。
互斥量對共享數據的保護就像一把鎖。在Pthreads中,任什麼時候候僅有一個線程能夠鎖定互斥量,所以,當多個線程嘗試去鎖定該互斥量時僅有一個會成功。直到鎖定互斥量的線程解鎖互斥量後,其餘線程才能夠去鎖定互斥量。線程必須輪着訪問受保護數據。
一個擁有互斥量的線程常常用於更新全局變量。確保了多個線程更新一樣的變量以安全的方式運行,最終的結果和一個線程處理的結果是相同的。這個更新的變量屬於一個「臨界區(critical section)」。html
使用互斥量的典型順序以下:
程序員
- 建立和初始一個互斥量
- 多個線程嘗試去鎖定該互斥量
- 僅有一個線程能夠成功鎖定改互斥量
- 鎖定成功的線程作一些處理
- 線程解鎖該互斥量
- 另一個線程得到互斥量,重複上述過程
- 最後銷燬互斥量
當多個線程競爭同一個互斥量時,失敗的線程會阻塞在lock調用處。能夠用「trylock」替換「lock」,則失敗時不會阻塞。當保護共享數據時,程序員有責任去確認是否須要使用互斥量。如,若四個線程會更新一樣的數據,但僅有一個線程用了互斥量,則數據可能會損壞。安全
建立和銷燬互斥量:
pthread_mutex_init (mutex,attr)
pthread_mutex_destroy (mutex)
pthread_mutexattr_init (attr)
pthread_mutexattr_destroy (attr)
用法:函數
互斥量必須用類型pthread_mutex_t類型聲明,在使用前必須初始化,這裏有兩種方法能夠初始化互斥量:
聲明時靜態地,如: pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
動態地用pthread_mutex_init()函數,這種方法容許設定互斥量的屬性對象attr。
互斥量初始化後是解鎖的。
attr對象用於設置互斥量對象的屬性,使用時必須聲明爲pthread_mutext_attr_t類型,默認值能夠是NULL。Pthreads標準定義了三種可選的互斥量屬性:post
- 協議(Protocol): 指定了協議用於阻止互斥量的優先級改變
- 優先級上限(Prioceiling):指定互斥量的優先級上限
- 進程共享(Process-shared):指定進程共享互斥量
注意全部實現都提供了這三個可先的互斥量屬性。
pthread_mutexattr_init()和pthread_mutexattr_destroy()函數分別用於建立和銷燬互斥量屬性對象。
pthread_mutex_destroy()應該用於釋放不須要再使用的互斥量對象。url
鎖定和解鎖互斥量:
函數:spa
pthread_mutex_lock (mutex)
pthread_mutex_trylock (mutex)
pthread_mutex_unlock (mutex)
用法:線程
線程用pthread_mutex_lock()函數去鎖定指定的mutex變量,若該mutex已經被另一個線程鎖定了,該調用將會阻塞線程直到mutex被解鎖。
pthread_mutex_trylock() will attempt to lock a mutex. However, if the mutex is already locked, the routine will return immediately with a "busy" error code. This routine may be useful in pthread_mutex_trylock().code
嘗試着去鎖定一個互斥量,然而,若互斥量已被鎖定,程序會馬上返回並返回一個忙錯誤值。該函數在優先級改變狀況下阻止死鎖是很是有用的。線程能夠用pthread_mutex_unlock()解鎖本身佔用的互斥量。在一個線程完成對保護數據的使用,而其它線程要得到互斥量在保護數據上工做時,能夠調用該函數。如有一下情形則會發生錯誤:htm
- 互斥量已經被解鎖
- 互斥量被另外一個線程佔用
互斥量並無多麼「神奇」的,實際上,它們就是參與的線程的「君子約定」。寫代碼時要確信正確地鎖定,解鎖互斥量。
Q:有多個線程等待同一個鎖定的互斥量,當互斥量被解鎖後,那個線程會第一個鎖定互斥量?
A:除非線程使用了優先級調度機制,不然,線程會被系統調度器去分配,那個線程會第一個鎖定互斥量是隨機的。
用例:
1 #include<stdlib.h>
2 #include<stdio.h> 3 #include<unistd.h> 4 #include<pthread.h> 5 6 typedef struct ct_sum 7 { 8 int sum; 9 pthread_mutex_t lock; 10 }ct_sum; 11 12 void * add1(void *cnt) 13 { 14 pthread_mutex_lock(&(((ct_sum*)cnt)->lock)); 15 for(int i=0; i < 50; i++) 16 { 17 (*(ct_sum*)cnt).sum += i; 18 } 19 pthread_mutex_unlock(&(((ct_sum*)cnt)->lock)); 20 pthread_exit(NULL); 21 return 0; 22 } 23 void * add2(void *cnt) 24 { 25 pthread_mutex_lock(&(((ct_sum*)cnt)->lock)); 26 for(int i=50; i<101; i++) 27 { 28 (*(ct_sum*)cnt).sum += i; 29 } 30 pthread_mutex_unlock(&(((ct_sum*)cnt)->lock)); 31 pthread_exit(NULL); 32 return 0; 33 } 34 35 int main(void) 36 { 37 pthread_t ptid1, ptid2; 38 ct_sum cnt; 39 pthread_mutex_init(&(cnt.lock), NULL); 40 cnt.sum=0; 41 42 pthread_create(&ptid1, NULL, add1, &cnt); 43 pthread_create(&ptid2, NULL, add2, &cnt); 44 45 pthread_join(ptid1,NULL); 46 pthread_join(ptid2,NULL); 47 48 printf("sum %d\n", cnt.sum); 49 pthread_mutex_destroy(&(cnt.lock)); 50 51 return 0; 52 }