八 Linux下執行緒的互斥

2021-09-22 12:21:24 字數 4614 閱讀 3336

為什麼使用執行緒鎖?

在多執行緒應用程式中,當多個執行緒共享相同的記憶體時,如同時訪問乙個變數時,需要確保每個執行緒看到一致的資料檢視,即保證所有執行緒對資料的修改是一致的。

如下兩種情況不存在不一致的問題:

每個執行緒使用的變數都是其他執行緒不會讀取和修改的

變數是唯讀的

當乙個執行緒在修改變數的值時,其他執行緒在讀取這個變數時可能會得到乙個不一致的值。

乙個典型的例子是,在乙個多執行緒程式中,兩個及以上個執行緒對同乙個變數i執行i++操作,結果得到的值並不如順序執行所預期的那樣。這就是執行緒間不同步的乙個例子。

可以用程式修改變數值時所經歷的三個步驟解釋這個現象:

從記憶體單元讀入暫存器

在暫存器中對變數操作(加/減1)

把新值寫回到記憶體單元

不能預期以上三步驟在乙個匯流排週期內完成,所以也就不能指望多執行緒程式如預期那樣執行。

多執行緒程式中可能會存在資料不一致的情況,那麼如何保證資料一致呢?可以考慮同一時間只有乙個執行緒訪問資料。互斥量(mutex)就是一把鎖。

多個執行緒只有一把鎖乙個鑰匙,誰上的鎖就只有誰能開鎖。當乙個執行緒要訪問乙個共享變數時,先用鎖把變數鎖住,然後再操作,操作完了之後再釋放掉鎖,完成。

當另乙個執行緒也要訪問這個變數時,發現這個變數被鎖住了,無法訪問,它就會一直等待,直到鎖沒了,它再給這個變數上個鎖,然後使用,使用完了釋放鎖,以此進行。

這個即使有多個執行緒同時訪問這個變數,也好象是對這個變數的操作是順序進行的。

互斥鎖(mutex)是一種簡單的加鎖的方法來控制對共享資源的訪問。

a. 靜態分配

pthread_mutex mutex = pthread_mutex_initializer;
b. 動態分配

互斥變數使用特定的資料型別:pthread_mutex_t,使用互斥量前要先初始化,使用的函式如下:

#include

intpthread_mutex_init

(pthread_mutex_t *restrict mutex,

const pthread_mutexattr_t *restrict attr)

;

其中 pthread_mutex_t 是乙個表示互斥量的聯合體型別,函式的第乙個引數是要初始化的互斥量,第二個引數是要設定的互斥量的屬性,引數二為空則表示使用預設的屬性。函式初始化互斥鎖成功返回0,否則返回非0。

靜態初始化的互斥量不需要銷毀,而對於動態初始化的互斥量則需要銷毀,其介面函式如下:

int

pthread_mutex_destroy

(pthread_mutex_t *mutex)

;

引數為要銷毀的互斥量,上面的初始化和銷毀的函式執行成功返回 0,出錯返回錯誤碼。

對互斥量加鎖解鎖的函式如下:

#include

intpthread_mutex_lock

(pthread_mutex_t *mutex)

;int

pthread_mutex_trylock

(pthread_mutex_t *mutex)

;int

pthread_mutex_unlock

(pthreadd_mutex_t *mutex)

;

第乙個函式 pthread_mutex_lock 對互斥量阻塞式加鎖,如果互斥量已經上鎖,則呼叫執行緒將則阻塞式等待,直到互斥量被解鎖。pthread_mutex_unlock 用於解鎖,如果不希望阻塞式的加鎖,則使用第二個函式 pthread_mutex_trylock ,該函式嘗試對互斥量加鎖,如果互斥量未被上鎖,則將互斥量鎖住,否則,該函式返回 ebusy。

atm_account.h

#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

atm_account.c

#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排程的物件,是乙個動態的概念。乙個程序之中至少包含有乙個或者多個執行緒。這些執行緒共享該程序空間的記憶體和檔案控制代碼資源,多個執行緒競爭地獲得這些資源。為了防止多個執行緒訪...