線程安全訪問之互斥量、死鎖和條件變量

今天,我們來說說互斥量和條件變量的API

線程安全

因爲進程中的線程共享了進行的虛擬地址空間,因此,線程間的通信變得更加簡單,但是缺點也隨之而來。這個缺點是:缺少數據的安全訪問控制,容易造成數據混亂。因此,我們必須使用互斥量和條件變量來維持數據的安全訪問。
我們把能造成數據混亂的情況總結了一個比較經典的模型:它們都是描述了多個線程/進程之間在數據訪問時候所應保持的關係。使得不會出現數據混亂和邏輯混亂問題。

生產者消費者模型

因此提出了同步與互斥,互斥量來解決線程間的互斥問題,條件變量來解決線程間的同步問題。

互斥量

臨界資源是需要受保護的。互斥量是用來實現線程間的互斥操作,具體用到是互斥鎖。互斥鎖也是一個臨界資源,所有的線程均要訪問它,互斥鎖本身就是一個原子操作。
實現線程間的互斥操作API;
1、定義一個互斥鎖:

pthread_mutex_t mutex;//定義了一個叫做mutex的互斥鎖

2、初始化互斥鎖:

靜態初始化互斥鎖。

//pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//靜態初始化的互斥鎖不需要釋放。

動態初始化互斥鎖。

int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
//mutex:互斥鎖名稱,即上面定義的mutex
//attr:初始化互斥鎖屬性,通常置爲NULL
//動態初始化的互斥鎖需要釋放。

3、對臨界資源進行加鎖、解鎖

加鎖:

int pthread_mutex_lock(pthread_mutex_t *mutex);//該函數爲阻塞加鎖,即沒有鎖資源時,一直等待直到有鎖資源時加鎖。
//mutex:上面初始化的mutex(鎖)

int pthread_mutex_trylock(pthread_mutex_t *mutex);//該函數爲非阻塞加鎖,即沒有鎖資源時,不等待直接報錯返回。
//mutex:上面初始化的mutex(鎖)

解鎖:

int pthread_mutex_unlock(pthread_mutex_t *mutex);
//mutex:上面初始化的mutex(鎖)

4、釋放互斥鎖:

int pthread_mutex_destroy(pthread_mutex_t *mutex);
//mutex:上面初始化的mutex(鎖)

對互斥鎖進行操作時,有加鎖就一定要有解鎖,並且必須在任意一個有可能退出的地方都要進行解鎖操作。否則會造成其他線程的鎖死。

死鎖

死鎖:多個線程對鎖資源進行競爭訪問。但是因爲線程推進順序不當,導致相互等待。使得線程無法繼續往下運行。
死鎖情況:因爲一直獲取不到鎖資源而造成的鎖死情況。
死鎖產生的必要條件:必須具備條件才能滿足。
1、互斥條件----A線程獲取了鎖資源,B線程就不能獲取該鎖資源。
2、請求與保持條件----A線程在拿到第一個鎖之後又去獲取第二把鎖,在沒有獲取到第二把鎖之前不釋放第一把鎖。
3、不可剝奪條件----A線程獲取了一把鎖,其他線程不能釋放A線程所獲取到的這把鎖。
4、環路等待條件----A線程拿了鎖1去請求鎖2,B線程拿了鎖2去請求鎖1
預防產生死鎖:破幻死鎖產生的必要條件。
死鎖避免:死鎖檢查算法,銀行家算法。

條件變量

條件變量是實現同步的機制。條件變量實現了等待+喚醒的操作機制。操作條件不滿足則等待,別人促使條件滿足了則喚醒等待隊列上的線程。
線程在對臨界資源訪問之前,先判斷臨界資源是否能夠操作,若可以則線程直接操作,若不能操作,則條件變量提供等待功能,讓該線程pcb等待在條件變量等待隊列上。

使用條件變量有以下步驟:
1、定義條件變量:

pthread_cond_t cond//定義一個叫做cond的條件變量。

2、條件變量初始化

靜態初始化條件變量:

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//靜態初始化的條件變量不需要手動釋放。

動態初始化條件變量:

int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
//cond:定義的條件變量名稱。
//attr:條件變量的屬性。
//動態初始化的條件變量需要手動釋放。

3、線程在判斷出條件不滿足的情況下提供等待功能:

等待abstime秒還不滿足時,報錯返回:

int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
//cond:條件變量名稱。
//:mutex:互斥鎖名稱。
//timespec:一個結構體,兩個成員分別是秒和納秒。

阻塞等待:

int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
//cond:條件變量名稱。
//mutex:互斥鎖名稱。

4、用戶在促使條件滿足後的,喚醒等待隊列上的線程。

喚醒等待隊列上的全部線程:

int pthread_cond_broadcast(pthread_cond_t *cond);
//cond:條件變量名稱。

喚醒等待隊列上的最早進來的第一個線程:

int pthread_cond_signal(pthread_cond_t *cond);
//cond:條件變量名稱。

5、銷燬條件變量:

pthread_cond_destroy(&cond);
//cond:條件變量名稱。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章