pThreads線程(二) 線程同步--互斥量/鎖


  互斥量(Mutex)是“mutual exclusion”的縮寫。互斥量是實現線程同步,和保護同時寫共享數據的主要方法。
  互斥量對共享數據的保護就像一把鎖。在Pthreads中,任何時候僅有一個線程可以鎖定互斥量,因此,當多個線程嘗試去鎖定該互斥量時僅有一個會成功。直到鎖定互斥量的線程解鎖互斥量后,其他線程才可以去鎖定互斥量。線程必須輪着訪問受保護數據。
  
一個擁有互斥量的線程經常用於更新全局變量。確保了多個線程更新同樣的變量以安全的方式運行,最終的結果和一個線程處理的結果是相同的。這個更新的變量屬於一個“臨界區(critical section)”。


  使用互斥量的典型順序如下:

  • 創建和初始一個互斥量
  • 多個線程嘗試去鎖定該互斥量
  • 僅有一個線程可以成功鎖定改互斥量
  • 鎖定成功的線程做一些處理
  • 線程解鎖該互斥量
  • 另外一個線程獲得互斥量,重復上述過程
  • 最后銷毀互斥量

  當多個線程競爭同一個互斥量時,失敗的線程會阻塞在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標准定義了三種可選的互斥量屬性:

  • 協議(Protocol): 指定了協議用於阻止互斥量的優先級改變
  • 優先級上限(Prioceiling):指定互斥量的優先級上限
  • 進程共享(Process-shared):指定進程共享互斥量

注意所有實現都提供了這三個可先的互斥量屬性。
pthread_mutexattr_init()和pthread_mutexattr_destroy()函數分別用於創建和銷毀互斥量屬性對象。
pthread_mutex_destroy()應該用於釋放不需要再使用的互斥量對象。

鎖定和解鎖互斥量:

函數

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().

  嘗試着去鎖定一個互斥量,然而,若互斥量已被鎖定,程序會立刻返回並返回一個忙錯誤值。該函數在優先級改變情況下阻止死鎖是非常有用的。線程可以用pthread_mutex_unlock()解鎖自己占用的互斥量。在一個線程完成對保護數據的使用,而其它線程要獲得互斥量在保護數據上工作時,可以調用該函數。若有一下情形則會發生錯誤:

  • 互斥量已經被解鎖
  • 互斥量被另一個線程占用

互斥量並沒有多么“神奇”的,實際上,它們就是參與的線程的“君子約定”。寫代碼時要確信正確地鎖定,解鎖互斥量。
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 }  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM