多線程編程2——線程同步

信號量
信號量通常有兩種:二進制信號量和計數信號量。二進制信號量只有0和1兩種取值,計數信號量有更大的取值範圍。
信號量一般用來保護一段代碼,使其每次只能被一個執行線程運行,要完成這個工作,可以使用二進制信號量。
有時,希望可以允許有限數目的線程執行一段指定的代碼,這時可以使用計數信號量。

創建

#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
//   功能:初始化一個未命名的信號量(unnamed semaphore)。

信號量控制

#include <semaphore.h>

int sem_post(sem_t *sem);   // v
int sem_wait(sem_t *sem);   // p

sem_post的作用是以原子操作的方式給信號量的值加1
sem_wait函數以原子操作的方式將信號量的值減1,但它會等待直到信號量有個非零值纔會開始減法操作。例如,對值爲2的信號量調用sem_wait,線程將繼續執行,但信號量的值會減到1。如果對值爲0的信號量調用sem_wait,這個函數就會等待,直到有其它線程增加了該信號量的值使其不再爲0爲止。
如果兩個線程同時在sem_wait函數上等待同一個信號量變爲非零值,那麼當該信號量被第三個線程增加1時,只有其中一個等待線程將開始對信號量減1,然後繼續執行,另外一個線程還將繼續等待。

信號量銷燬

#include <semaphore.h>
int sem_destroy(sem_t *sem);
//這個函數的作用是,用完信號量後對它進行清理,清理該信號量所擁有的資源。如果你試圖清理的信號量正被一些線程等待,就會收到一個錯誤。

多線程併發應用程序有一個經典的模型,即生產者/消費者模型。系統中,產生消息的是生產者,處理消息的是消費者,消費者和生產者通過一個緩衝區進行消息傳遞。生產者產生消息後提交到緩衝區,然後通知消費者可以從中取出消息進行處理。消費者處理完信息後,通知生產者可以繼續提供消息。
要實現這個模型,關鍵在於消費者和生產者這兩個線程進行同步。也就是說:只有緩衝區中有消息時,消費者才能夠提取消息;只有消息已被處理,生產者才能產生消息提交到緩衝區。

互斥量
互斥量(mutex)從概念上來說類似於一個二進制信號量,即初始值爲1的信號量。互斥量被獲取之後就不能再被獲取,因此對互斥體的獲取和釋放操作常常稱爲加鎖和解鎖操作。
互斥量只能由獲取它的線程進行釋放,如果違反這一原則,則結果是未定義的。
互斥量從本質上說是一把鎖,在訪問共享資源前對互斥量進行加鎖,在訪問完成後釋放互斥量上的鎖。對互斥量進行加鎖以後,任何其他試圖再次對互斥量加鎖的線程將會被阻塞直到當前線程釋放該互斥量。

初始化
互斥量用一個pthread_mutex_t型的變量表示。使用互斥量之前需要對它進行初始化,其接口函數原型如下:
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
mutex參數指向要初始化的互斥量。attr參數指向一個描述互斥量屬性的結構體。attr參數可以爲NULL,表示使用默認屬性。

操作函數
互斥量的主要操作函數如下:
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
pthread_mutex_lock()用於對mutex參數指向的互斥量進行加鎖。如果這時互斥量已經被鎖,則調用這個函數的線程將被阻塞,直到互斥量成爲未鎖狀態。函數返回時,表示這個互斥量已經變爲已鎖狀態,同時,函數的調用者成爲這個互斥量的擁有者。
pthread_mutex_trylock()也用於對mutex參數指向的互斥量進行加鎖。如果這時互斥量已經被鎖,則函數以錯誤狀態返回。
pthread_mutex_unlock()用於對mutex參數指向的互斥量進行解鎖。如果這時互斥量是未鎖狀態或不是當前線程所擁有的,則結果未定義。 因此,互斥量必須在同一線程上成對出現。

銷燬
互斥量不用以後,應該使用下面的函數進行銷燬:
int pthread_mutex_destroy(pthread_mutex_t *mutex);

條件變量

假設有這樣一種情況:線程正在等待共享數據內某個條件出現,這時必須先解鎖,否則其他線程不可能更改共享數據。一種實現方式是,可以循環檢測共享數據,但是在檢測前要加鎖,檢測後又要解鎖,這樣效率會很低。
因此,在這種情況下,需要一種方法,使得當線程在等待某些條件的滿足時進入睡眠狀態,一旦條件滿足,線程就應該被喚醒繼續執行。這個方法就是使用POSIX條件變量。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章