linux下的同步與互斥

來源:互聯網
上載者:User

linux下的同步與互斥   談到linux的並發,必然涉及到線程之間的同步和互斥,linux主要為我們提供了幾種實現線程間同步互斥的 機制,本文主要介紹互斥鎖,條件變數和訊號量。互斥鎖和條件變數包含在pthread線程庫中,使用時需要包含 <pthread.h>標頭檔。而使用訊號量時需要包含<semaphore.h>標頭檔。 1.互斥鎖     型別宣告:pthread_mutex_t mutex;     對互斥量的初始化:         程式在使用pthread_mutex_t之前需要先對其進行初始化,對於靜態分配的pthread_mutex_t變數來說,         只要將PTHREAD_MUTEX_INITIALIZER賦給變數就行了,語句如下:             static pthread_mutex_t mutex=PTHREAD_mutex_INITIALIZER;         而對於動態分配或沒有預設互斥屬性的互斥變數來說,要調用pthread_mutex_init函數來執行初始化工         作。函式宣告如下:             int pthread_mutex_init(pthread_mutex_t* mutex,const pthread_mutexattr_t* attr);         mutex是指向一個互斥量的指標,attr是指向一個屬性結構體的指標,為NULL時使用預設屬性。         需要注意的是pthread_mutex_init函數只能恰好執行一次,重複執行的結果是未定義的。     對互斥量的操作:         int pthread_mutex_lock(pthread_mutex_t* mutex);//對互斥量執行鎖定操作         int pthread_mutex_unlock(pthread_mutex_t* mutex);//對互斥量執行解鎖操作     對互斥量的銷毀:         int pthread_mutex_destroy(pthread_mutex_t* mutex);//     使用方法:         以下代碼用互斥量來保護一個臨界區:         pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;//初始化         pthread_mutex_lock(&mutex);//獲得鎖         /*critical section code*/         pthread_mutex_unlock(&mutex);//釋放鎖     通常比較適用的方法是將編寫一組訪問臨界區的函數,將鎖定調用都放在這些函數中,這是確保對對象的拍他     性訪問的一種方法,這樣鎖定機制對調用線程就是透明的了。      2.條件變數     有時,我們可能需要讓線程在某個條件滿足之前一直等待,在未使用條件變數之前,您可能會使用忙等待,如     下列代碼:         while(x!=y);     這樣的方式,然而這種佔著茅坑不拉屎的行為是非常不被提倡的。因此,我們引入條件變數的概念來是線程在     某個條件不滿足是進入掛起狀態。     型別宣告:pthread_cond_t cond;     對條件變數的初始化:         程式在使用pthread_cond_t變數之前必須對其進行初始化。對於靜態分配的pthread_cond_t變數來說,         只要將PTHREAD_COND_INITIALIZER賦給變數就星了,語句如下:         pthread_cond_t cond=PTHREAD_COND_INITIALIZER;     對於動態分配的或沒有預設屬性的變數來說,就要調用pthread_cond_init函數來執行初始化。函式宣告如下:         int pthread_cond_init(pthread_cond_t* cond,const pthread_cond_attr_t* attr);         cond是指向一個條件變數的指標,attr是指向一個屬性結構體的指標,為NULL時使用預設屬性。     對條件變數的操作:         int pthread_cond_wait(pthread_cond_* cond,pthread_mutex_t* mutex);//使線程阻塞於某個條件。         int pthread_cond_signal(pthread_cond_t* cond);//喚醒某個阻塞在cond上的線程。     對條件變數的銷毀:         int pthread_cond_destroy(pthread_cond_t* cond);     使用方法:         條件變數是與斷言或條件的測試一同調用的,以此來實現將條件變數關聯到某個斷言上去。通常線程會對         一個條件進行測試,如果失敗,就會調用pthread_cond_wait函數將線程阻塞。範例程式碼如下:             pthread_mutex_lock(&mutex);             while( a<b )                 pthread_cond_wait(&cond,&mutex);             pthread_mutex_unlock(&mutex);         調用線程應該在它測試或調用pthread_cond_wait之前獲得一個互斥量,以避免在測試條件的時候有其他         線程改寫條件中變數的值。pthread_cond_wait函數中第二個參數是一個互斥量類型的指標,線程在調用         pthread_cond_wait後會隱式的原子地釋放mutex互斥量並阻塞,允許其他線程獲得互斥量並修改斷言中         的變數。當線程成功的從pthread_cond_wait中返回時,它就再次擁有了互斥量,並且不用顯式的重新獲         得互斥量。         當其他線程修改了斷言中變數的值後可以調用pthread_cond_signal函數來喚醒一個等待在某個斷言成真         的線程。也可以使用pthread_cond_broadcast(pthread_cond_t*)函數來喚醒所有等待在某個條件變數         上的線程。在修改斷言中出現的任一變數之前要獲得互斥量。範例程式碼如下:             pthread_mutex_lock(&mutex);             a++;             pthread_cond_signal(&cond);//pthread_cond_broadcast(&cond);             pthread_mutex_unlock(&mutex);              3.訊號量     訊號量是一個整型變數,它帶有兩個原子操作wait和signal。wait操作還可以被稱為down、P操作。signal操     作還可以被稱為up、V、post操作。     如果S大於0,wait操作就在一個原子操作中對其進行減量運算。如果S等於0,wait操作就就在一個原子操作中     測試S,阻塞調用程式,將調用程式放入wait的等待隊列中。     如果有線程在訊號量上阻塞,則S必然等於0,signal操作就會解除對某一個等待線程的阻塞。如果S大於0,即     沒有線程阻塞在訊號量上,signal就對S進行增量操作。     可以把訊號量理解為臨界區中資源的可用數量,wait表示對資源的申請,當沒有可用資源時訊號量為0,signal     表示線程使用資源後,對資源的釋放。     下面介紹幾種通過訊號量來控制線程按某種順序執行的方法:     1.線程1中a先於線程2中b執行[S初始話為0]         Process 1:             a;             signal(&S);         Process 2:             wait(&S);             b;     2.線程1中a於線程2中b語句交替執行[S,Q初始化為1]         Process 1:             while(1){                 wait(&S);                 a;                 signal(&Q);             }         Process 2:             while(1){                 wait(&Q);                 b;                 signal(&S);             }     可通過讓S為0Q為1,或讓S為1Q為0,來保證讓a或b先執行。     需要注意的是,為了避免申請多個資源發生死結,應按照相同的順序申請資源,這裡公司面試的時候經常會被     問到。               linux中訊號量有無名訊號量和命名訊號量之分,無名訊號量可用於線程之間的同步和互斥,命名訊號量可用     於進程間的通訊,命名訊號量與具名管道相似,以檔案的形式儲存於磁碟上。        無名訊號量:     型別宣告:         sem_t sem;     初始化:         int sem_init(sem_t* sem,int pshared,int value);         參數pshared為0,表示訊號量只能由初始化這個訊號量的進程中的線程使用。         value表示要將sem初始化的值。value不能為負。     操作:         int sem_post(sem_t* sem);//signal操作         int sem_wait(sem_t* sem);//wait操作     銷毀:         int sem_destroy(sem_t* sem);     使用方法:         通常先由主線程調用sem_init對訊號量進行初始化。然後在其他線程中調用post或wait函數。範例程式碼         如下:             static sem_t sem;             sem_init(&sem,0,1);             sem_wait(&sem);             /*critical section*/             sem_post(&sem);            命名訊號量:     型別宣告:         sem_t sem;     初始化:         sem_t* sem_open(const char* name,int oflag,...);         參數oflag用來確定是建立訊號量,還是僅僅由函數對其訪問。若oflag中的O_CREAT位元位被設定,則需         要另外兩個參數,mode_t mode為檔案許可權,unsigned value為訊號量值。     關閉:         int sem_close(sem_t* sem);     刪除:         int sem_unlink(sem_t* sem);     操作方式與無名訊號量相同。  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.