一、互斥量的概念
互斥量從本質來說是一把鎖,在訪問共享資源前對互斥量進行設定(加鎖),在訪問完成後釋放(解鎖)互斥量。對互斥量進行加鎖以後,任何其他試圖再次對互斥量加鎖的執行緒都會被阻塞,直到當前執行緒釋放該互斥鎖。如果解鎖前有乙個以上的執行緒阻塞,那麼解鎖後這些執行緒就變為執行狀態,直到其中乙個執行緒重新對互斥量加鎖,這時其他執行緒又變為阻塞狀態。
#include
#include
#include
#include
#include
int ticket = 10;
void *route(void *arg)
else
}}int main(void)
執行結果:
分析:為什麼不能獲得正確的結果?
(1)if語句判斷條件為真以後,**會併發地切換到其他執行緒;
(2)usleep這個模擬漫長業務的過程,在這個漫長的業務過程中,可能有很多個執行緒會進入該**段;
(3)ticket操作本身就不是乙個原子操作。
證:取出ticket的部分彙編**
可見:該操作並不是原子操作,而是對應多條指令
1)load:將共享變數ticket從記憶體載入到暫存器中;
2)update:更新暫存器裡面的值,執行-1操作;
3)store:將新值從暫存器寫到共享變數ticket的記憶體位址。
假設:剩下2張票,但是有4個人同時購買,就會出現執行結果中的-2張票,這樣可以嗎?顯然是錯誤的!
要解決以上問題,需要做到三點:
1)**必須要有互斥行為:當乙個執行緒進入臨界區執行時,不允許其他執行緒再進入該臨界區。
2)如果多個執行緒同時要求執行臨界區**,並且臨界區沒有執行緒執行,那麼只能允許乙個執行緒進入臨界區。
3)如果執行緒不在臨界區中執行,那麼該執行緒不能阻止其他執行緒進入臨界區。
如下圖所示:
三、互斥量的介面函式
1、初始化互斥量
初始化互斥量的兩種方法:
(1)方法一:靜態分配:
pthread_mutex_t mutex = pthread_mutex_initializer
(2)方法二:動態分配:
1)函式原型:int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
2)引數:
mutex:要初始化的互斥量;
attr:null,表示預設屬性;
3)返回值:成功返回0;否則返回錯誤編號。
2、銷毀互斥量——
如果動態分配互斥量(例如,通過呼叫malloc函式),需要呼叫pthread_mutex_destroy函式釋放記憶體。
(1)函式原型:int pthread_mutex_destroy(pthread_mutex_t *mutex);
(2)引數:mutex,表示要初始化的互斥量;
(3)返回值:成功返回0;否則返回錯誤編號。
(4)銷毀互斥量需要注意:
a、使用pthread_mutex_initializer初始化的互斥量不需要銷毀;
b、不要銷毀乙個已經加鎖的互斥量;
c、已經銷毀的互斥量,要確保後面不會有執行緒在嘗試加鎖。
3、互斥量加鎖和解鎖
(1)函式原型:
1)int pthread_mutex_lock(pthread_mutex_t *mutex);
2)int pthread_mutex_trylock(pthread-mutex_t *mutex);
3)int pthread_mutex_unlock(pthread_mutex_t *mutex);
(2)引數:mutex,表示要初始化的互斥量;
(3)返回值:成功返回0,失敗返回錯誤號
(4)釋:加鎖時,可能會遇到以下情況:
1)互斥量處於未鎖狀態,該函式會將互斥量鎖定,同時返回成功。
2)發起函式呼叫時,其他執行緒已經鎖定互斥量,或者存在其他執行緒同時申請互斥量,但是沒有競爭到互斥量,那麼pthread_lock呼叫會陷入阻塞,等待互斥量解鎖。
3)如果執行緒不希望阻塞,它可以使用pthread_mutex_trylock嘗試對互斥量進行加鎖。
【例】改進上面的售票系統
#include
#include
#include
#include
#include
#include
int ticket = 10;
pthread_mutex_t mutex;
void *route(void *arg)
else
}}int main(void)
釋:sched_yield()這個函式可以讓等於或高於當前執行緒的執行緒先執行。如果沒有符合條件的執行緒,那麼這個函式將會立刻返回然後繼續執行當前執行緒的程式。 在成功完成之後返回零,否則返回-1。
執行結果:
執行緒同步 互斥量
下面以乙個簡單的多執行緒程式來演示如何使用互斥量來進行執行緒同步。在主線程中,我們建立子執行緒,並把陣列msg作為引數傳遞給子執行緒,然後主線程呼叫函式pthread mutex lock對互斥量加鎖,等待輸入,輸入完成後,呼叫函式pthread mutex unlock對互斥量解鎖,從而使執行緒函...
執行緒同步 互斥量
互斥量的使用 執行緒同步之互斥量 include include include include include include include using namespace std 全域性變數,兩個執行緒都可以修改,因此修改的時候需要加鎖 int g value 0 互斥量 pthread mu...
POSIX執行緒 互斥量
為什麼需要互斥量 執行緒最大的好處是它們可以通過全域性變數來共享資訊。但這個好處也帶來了麻煩 有可能很多執行緒同時修改某乙個全域性變數,導致該全域性變數出現錯誤。我們必須制定某些規則,使執行緒對該全域性變數的修改不會導致錯誤。這個規則就是 同步。posix執行緒使用互斥量來進行同步,經驗表明,正確使...