為什麼使用執行緒鎖?
在多執行緒應用程式中,當多個執行緒共享相同的記憶體時,如同時訪問乙個變數時,需要確保每個執行緒看到一致的資料檢視,即保證所有執行緒對資料的修改是一致的。
如下兩種情況不存在不一致的問題:
每個執行緒使用的變數都是其他執行緒不會讀取和修改的
變數是唯讀的
當乙個執行緒在修改變數的值時,其他執行緒在讀取這個變數時可能會得到乙個不一致的值。
乙個典型的例子是,在乙個多執行緒程式中,兩個及以上個執行緒對同乙個變數i執行i++操作,結果得到的值並不如順序執行所預期的那樣。這就是執行緒間不同步的乙個例子。
可以用程式修改變數值時所經歷的三個步驟解釋這個現象:
從記憶體單元讀入暫存器
在暫存器中對變數操作(加/減1)
把新值寫回到記憶體單元
不能預期以上三步驟在乙個匯流排週期內完成,所以也就不能指望多執行緒程式如預期那樣執行。
多執行緒程式中可能會存在資料不一致的情況,那麼如何保證資料一致呢?可以考慮同一時間只有乙個執行緒訪問資料。互斥量(mutex)就是一把鎖。
多個執行緒只有一把鎖乙個鑰匙,誰上的鎖就只有誰能開鎖。當乙個執行緒要訪問乙個共享變數時,先用鎖把變數鎖住,然後再操作,操作完了之後再釋放掉鎖,完成。
當另乙個執行緒也要訪問這個變數時,發現這個變數被鎖住了,無法訪問,它就會一直等待,直到鎖沒了,它再給這個變數上個鎖,然後使用,使用完了釋放鎖,以此進行。
這個即使有多個執行緒同時訪問這個變數,也好象是對這個變數的操作是順序進行的。
互斥鎖(mutex)是一種簡單的加鎖的方法來控制對共享資源的訪問。
a. 靜態分配
pthread_mutex mutex = pthread_mutex_initializer;
b. 動態分配
互斥變數使用特定的資料型別:pthread_mutex_t,使用互斥量前要先初始化,使用的函式如下:
其中 pthread_mutex_t 是乙個表示互斥量的聯合體型別,函式的第乙個引數是要初始化的互斥量,第二個引數是要設定的互斥量的屬性,引數二為空則表示使用預設的屬性。函式初始化互斥鎖成功返回0,否則返回非0。#include
intpthread_mutex_init
(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr)
;
靜態初始化的互斥量不需要銷毀,而對於動態初始化的互斥量則需要銷毀,其介面函式如下:
引數為要銷毀的互斥量,上面的初始化和銷毀的函式執行成功返回 0,出錯返回錯誤碼。int
pthread_mutex_destroy
(pthread_mutex_t *mutex)
;
對互斥量加鎖解鎖的函式如下:
第乙個函式 pthread_mutex_lock 對互斥量阻塞式加鎖,如果互斥量已經上鎖,則呼叫執行緒將則阻塞式等待,直到互斥量被解鎖。pthread_mutex_unlock 用於解鎖,如果不希望阻塞式的加鎖,則使用第二個函式 pthread_mutex_trylock ,該函式嘗試對互斥量加鎖,如果互斥量未被上鎖,則將互斥量鎖住,否則,該函式返回 ebusy。#include
intpthread_mutex_lock
(pthread_mutex_t *mutex)
;int
pthread_mutex_trylock
(pthread_mutex_t *mutex)
;int
pthread_mutex_unlock
(pthreadd_mutex_t *mutex)
;
atm_account.h
atm_account.c#ifndef __atm_account_h__
#define __atm_account_h__
#include
#include
#include
#include
#include
#include
#include
/** 賬戶資訊 */
typedef
struct
atm_account;
/** 建立賬戶 */
extern atm_account *
atm_account_create
(int code,
double balance)
;/** 銷毀賬戶 */
extern
void
atm_account_destroy
(atm_account *account)
;/** 取款 */
extern
double
atm_account_withdraw
(atm_account *account,
double amt)
;/** 存款 */
extern
double
atm_account_desposit
(atm_account *account,
double amt)
;/** 檢視賬戶餘額 */
extern
double
atm_account_balanceget
(atm_account *account)
;#endif
從執行的結果可知,對共享資源加鎖後,對資源的訪問就存在互斥的關係,將不會出現上述錯誤,男孩操作賬戶對共享資源操作時,女孩是不能操作共享資源的。#include
"atm_account.h"
/** 建立賬戶 */
atm_account *
atm_account_create
(int code,
double balance)
account->code = code;
account->balance = balance;
/** 對互斥鎖進行初始化 */
pthread_mutex_init
(&account->mutex,
null);
return account;
}/** 銷毀賬戶 */
void
atm_account_destroy
(atm_account *account)
pthread_mutex_destroy
(&account->mutex)
;free
(account);}
/** 取款: 成功,則返回取款金額 */
double
atm_account_withdraw
(atm_account *account,
double amt)
/** 對共享資源(賬戶進行加鎖) */
pthread_mutex_lock
(&account->mutex);if
(amt <
0|| amt > account->balance)
double balance_tmp = account->balance;
sleep(1
);balance_tmp -
= amt;
account->balance = balance_tmp;
pthread_mutex_unlock
(&account->mutex)
;return amt;
}/** 存款: 返回存款的金額 */
double
atm_account_desposit
(atm_account *account,
double amt)
/** 對共享資源(賬戶進行加鎖) */
pthread_mutex_lock
(&account->mutex);if
(amt <0)
double balance_tmp = account->balance;
sleep(1
);balance_tmp +
= amt;
account->balance = balance_tmp;
pthread_mutex_unlock
(&account->mutex)
;return amt;
}/** 檢視賬戶餘額 */
double
atm_account_balanceget
(atm_account *account)
/** 對共享資源(賬戶進行加鎖) */
pthread_mutex_lock
(&account->mutex)
;double balance_tmp = account->balance;
pthread_mutex_unlock
(&account->mutex)
;return balance_tmp;
}
Linux環境下執行緒的互斥
多個執行緒同時訪問共享資料時可能會衝突,這跟前面講訊號時所說的可重入性是同樣的問 題。比如 兩個執行緒都要把某個全域性變數增加1,這個操作在某平台需要三條指令完成 1.從記憶體讀變數值到暫存器 2.暫存器的值加1 3.將暫存器的值寫回記憶體 假設兩個執行緒在多處理器平台上同時執行這三條指令,則可能導...
linux下執行緒同步之互斥鎖
互斥鎖是多執行緒同步的一種方式,當多個執行緒訪問同乙個變數時,最簡單的方法就是使用乙個互斥鎖 mutex 保護這個共享變數,防止出現資源搶占的問題。下面是未加互斥鎖時 include includepthread mutex t mutex pthread mutex initializer 靜態初...
Linux下執行緒同步物件 1 互斥量
程序是linux資源分配的物件,linux會為程序分配虛擬記憶體 4g 和檔案控制代碼等資源,是乙個靜態的概念。執行緒是cpu排程的物件,是乙個動態的概念。乙個程序之中至少包含有乙個或者多個執行緒。這些執行緒共享該程序空間的記憶體和檔案控制代碼資源,多個執行緒競爭地獲得這些資源。為了防止多個執行緒訪...