首頁  >  文章  >  後端開發  >  Linux--線程的同步與互斥

Linux--線程的同步與互斥

黄舟
黄舟原創
2017-01-18 10:32:421475瀏覽

一、 mutex互斥
同步:就是對資源的存取有序。互斥:就是任一時刻來說只有一個在執行;但是對於多線程的程式來說,訪問衝突的問題是很普遍的,解決的辦法是引入互斥鎖(Mutex,MutualExclusive Lock),獲得鎖的線程可以完成“讀-修改-寫”的操作,然後釋放鎖給其它線程,沒有獲得鎖的線程只能等待而不能訪問共享數據,這樣“讀-修改-寫”三步操作組成一個原子操作,要么都執行,要么都不執行,不會執行到中間被打斷,也不會在其它處理器上並行做這個操作。
互斥鎖用pthread_mutex_t類型的變數表示。用pthread_mutex_init初始化,用hread_destory()銷毀。成功回傳0,失敗回傳錯誤號。 。如果Mutex變數是靜態分配的(全域變數或static變數),也可以用巨集定義PTHREAD_MUTEX_INITIALIZER來初始化,相當於用pthread_mutex_init初始化並且attr參數為NULL
一個執行緒可以呼叫pthread_mutex_lock獲得Mutex,如果這時獲得另一個執行緒已經調pthread_mutex_lock獲得了該Mutex,則當前線程需要掛起等待,直到另一個線程調用pthread_mutex_unlock釋放Mutex,當前線程被喚醒,才能獲得該Mutex並繼續執行。意思是說如果有一個線程對mutex上了鎖,沒有開鎖,另外一個線程想獲得mutex,就得掛機等待,直到上鎖的線程開了鎖釋放開mutex之後,該線程被喚醒,才能獲得mutex.
如果一個線程既想獲得鎖,又不想掛起等待,可以調用pthread_mutex_trylock,如果Mutex已經被另一個線程獲得,這個函數會失敗返回EBUSY,而不會使線程掛起等待。

1 #include<stdio.h>  
  2 #include<stdlib.h>  
  3 #include<pthread.h>  
  4 static int g_count=0;  
  5 void * addWrite(void * arg)  
  6 {  
  7     int count=0;  
  8     int value=0;  
  9     while(count++ <5000)  
 10     {  
 11         value=g_count;  
 12         printf("g_count is %d\n",g_count);  
 13         g_count=value+1;  
 14     }  
 15 }  
 16 int main()  
 17 {  
 18     pthread_t id1;  
 19     pthread_t id2;  
 20     int ret=pthread_create(&id1,NULL,addWrite,NULL);  
 21     int res=pthread_create(&id2,NULL,addWrite,NULL);  
 22     pthread_join(id1,NULL);  
 23     pthread_join(id2,NULL);

我們創建兩個線程,各自把g_count增加5000次,正常情況下最後counter應該等於10000,但事實上每次運行該程式的結果都不一樣,有時候數到5000多,有時數到6000多但是加上鎖之後(在)第五行加上pthread_mutex_init 如下圖

Linux--線程的同步與互斥

結果:

Linux--線程的同步與互斥

加上鎖之後,就輸出10000
二、lock和unlock的實現原理

為了實現互斥鎖操作,大多數體系結構都提供了swap或exchange指令,該指令的作用是把寄存器和內存單元的數據相交換,由於只有一條指令,保證了原子性,即使是多處理器平台,訪問記憶體的匯流排週期也有先後,一個處理器上的交換指令執行時另一個處理器的交換指令只能等待匯流排週期。如下圖的偽代碼所示。 unlock中的釋放鎖定操作同樣只用一條指令實現,以保證它的原子性。

Linux--線程的同步與互斥

三、死鎖
・一般情況下,如果同一個線程先後兩次調用lock,在第二次調用時,由於鎖已經被佔用,該線程會掛起等待別的線程釋放鎖,然而鎖正是被自己佔用著的,該線程又被掛起而沒有機會釋放鎖,因此就永遠處於掛起等待狀態了,這叫做死鎖(Deadlock)。另一種典型的死鎖情形是這樣:線程A獲得了鎖1,線程B獲得了鎖2,這時線程A調用lock試圖獲得鎖2,結果是需要掛起等待線程B釋放鎖2,而這時線程B也調用lock試圖獲得鎖1,結果是需要掛起等待線程A釋放鎖1,於是線程A和B都永遠處於掛起狀態了。
死鎖形成的條件
①、互斥條件:一個資源每次只能被一個執行緒使用。
②、請求與保持條件:當一個行程因請求資源而被阻塞時,對已取得的資源保持不放。

③、不剝奪條件:進程已獲得的資源,在未使用完之前,不能強行剝奪。

④循環等待條件:若干進程之間形成一種頭尾相接的循環等待資源關係

如果涉及到更多的線程和更多的鎖,則更容易引起死鎖問題。寫程式時應該盡量避免同時獲得多個鎖,如果一定有必要這麼做,則有一個原則:如果所有執行緒在需要多個鎖時都按相同的先後順序(常見的是按Mutex變數的地址順序)獲得鎖,則不會出現死鎖。例如一個程式中用到鎖1、鎖2、鎖3,它們所對應的Mutex變數的位址是鎖1

以上就是Linux--線程的同步與互斥的內容,更多相關內容請關注PHP中文網(www.php.cn)!


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn