多執行緒程式設計 互斥鎖

2021-08-16 22:13:35 字數 4846 閱讀 2308

多執行緒程式設計-互斥鎖 

1.引言:

互斥鎖,是一種訊號量,常用來防止兩個程序或執行緒在同一時刻訪問相同的共享資源。可以保證以下三點:

1)、原子性:把乙個互斥量鎖定為乙個原子操作,這意味著作業系統(或pthread函式庫)保證了如果乙個執行緒鎖定了乙個互斥量,沒有其他執行緒在同一時間可以成功鎖定這個互斥量。

2)、唯一性:如果乙個執行緒鎖定了乙個互斥量,在它解除鎖定之前,沒有其他執行緒可以鎖定這個互斥量。

3)、非繁忙等待:如果乙個執行緒已經鎖定了乙個互斥量,第二個執行緒又試圖去鎖定這個互斥量,則第二個執行緒將被掛起(不占用任何cpu資源),直到第乙個執行緒解除對這個互斥量的鎖定為止,第二個執行緒則被喚醒並繼續執行,同時鎖定這個互斥量。

從以上三點,我們看出可以用互斥量來保證對變數(關鍵的**段)的排他性訪問。

2.函式說明:

需要的標頭檔案:pthread.h

1)初始化互斥鎖

函式原型:int  

pthread_mutex_init(pthread_mutex_t *mp, const pthread_mutexattr_t *mattr)

初始化互斥鎖之前,必須將其所在的記憶體清零。

如果互斥鎖已初始化,則它會處於未鎖定狀態。互斥鎖可以位於程序之間共享的記憶體中或者某個程序的專用記憶體中。

2)鎖定互斥鎖

函式原型:

int

pthread_mutex_lock(pthread_mutex_t *mutex); #include pthread_mutex_t mutex; int ret; ret = pthread_ mutex_lock(&mp); /* acquire the mutex */

函式說明:

當 pthread_mutex_lock() 返回時,該互斥鎖已被鎖定。呼叫執行緒是該互斥鎖的屬主。如果該互斥鎖已被另乙個執行緒鎖定和擁有,則呼叫執行緒將阻塞,直到該互斥鎖變為可用為止。

如果互斥鎖型別為 pthread_mutex_normal,則不提供死鎖檢測。嘗試重新鎖定互斥鎖會導致死鎖。如果某個執行緒嘗試解除鎖定的互斥鎖不是由該執行緒鎖定或未鎖定,則將產生不確定的行為。

如果互斥鎖型別為 pthread_mutex_errorcheck,則會提供錯誤檢查。如果某個執行緒嘗試重新鎖定的互斥鎖已經由該執行緒鎖定,則將返回錯誤。如果某個執行緒嘗試解除鎖定的互斥鎖不是由該執行緒鎖定或者未鎖定,則將返回錯誤。

如果互斥鎖型別為 pthread_mutex_recursive,則該互斥鎖會保留鎖定計數這一概念。執行緒首次成功獲取互斥鎖時,鎖定計數會設定為 1。執行緒每重新鎖定該互斥鎖一次,鎖定計數就增加 1。執行緒每解除鎖定該互斥鎖一次,鎖定計數就減小 1。 鎖定計數達到 0 時,該互斥鎖即可供其他執行緒獲取。如果某個執行緒嘗試解除鎖定的互斥鎖不是由該執行緒鎖定或者未鎖定,則將返回錯誤。

如果互斥鎖型別是 pthread_mutex_default,則嘗試以遞迴方式鎖定該互斥鎖將產生不確定的行為。對於不是由呼叫執行緒鎖定的互斥鎖,如果嘗試解除對它的鎖定,則會產生不確定的行為。如果嘗試解除鎖定尚未鎖定的互斥鎖,則會產生不確定的行為。

返回值:

pthread_mutex_lock() 在成功完成之後會返回零。其他任何返回值都表示出現了錯誤。如果出現以下任一情況,該函式將失敗並返回對應的值。

eagain:由於已超出了互斥鎖遞迴鎖定的最大次數,因此無法獲取該互斥鎖。

edeadlk:當前執行緒已經擁有互斥鎖。

3)解除鎖定互斥鎖

函式原型:

int

pthread_mutex_unlock(pthread_mutex_t *mutex); #include pthread_mutex_t mutex; int ret; ret = pthread_mutex_unlock(&mutex); /* release the mutex */

函式說明:pthread_mutex_unlock() 可釋放 mutex 引用的互斥鎖物件。互斥鎖的釋放方式取決於互斥鎖的型別屬性。如果呼叫 pthread_mutex_unlock() 時有多個執行緒被 mutex 物件阻塞,則互斥鎖變為可用時排程策略可確定獲取該互斥鎖的執行緒。對於 pthread_mutex_recursive 型別的互斥鎖,當計數達到零並且呼叫執行緒不再對該互斥鎖進行任何鎖定時,該互斥鎖將變為可用。

返回值:pthread_mutex_unlock() 在成功完成之後會返回零。

其他任何返回值都表示出現了錯誤。如果出現以下情況,該函式將失敗並返回對應的值。

eperm :當前執行緒不擁有互斥鎖。

4)使用非阻塞互斥鎖鎖定

函式原型:

int

pthread_mutex_trylock(pthread_mutex_t *mutex); #include pthread_mutex_t mutex; int ret; ret = pthread_mutex_trylock(&mutex); /* try to lock the mutex */

函式說明:pthread_mutex_trylock() 是 pthread_mutex_lock() 的非阻塞版本。如果 mutex 所引用的互斥物件當前被任何執行緒(包括當前執行緒)鎖定,則將立即返回該呼叫。否則,該互斥鎖將處於鎖定狀態,呼叫執行緒是其屬主。

返回值:pthread_mutex_trylock() 在成功完成之後會返回零。其他任何返回值都表示出現了錯誤。如果出現以下任一情況,該函式將失敗並返回對應的值。

ebusy :

由於 mutex 所指向的互斥鎖已鎖定,因此無法獲取該互斥鎖。

eagain:描述:

由於已超出了 mutex 的遞迴鎖定最大次數,因此無法獲取該互斥鎖。

5)銷毀互斥鎖

函式原型:

int

pthread_mutex_destroy(pthread_mutex_t *mp); #include pthread_mutex_t mp; int ret; ret = pthread_mutex_destroy(&mp); /* mutex is destroyed */請注意,沒有釋放用來儲存互斥鎖的空間。

返回值:

pthread_mutex_destroy() 在成功完成之後會返回零。其他任何返回值都表示出現了錯誤。如果出現以下任一情況,該函式將失敗並返回對應的值。

einval: mp 指定的值不會引用已初始化的互斥鎖物件。

3.例子:

互斥鎖用來保證一段時間內只有乙個執行緒在執行一段**。必要性顯而易見:假設各個執行緒向同乙個檔案順序寫入資料,最後得到的結果一定是災難性的。

我們先看下面一段**。這是乙個讀/寫程式,它們公用乙個緩衝區,並且我們假定乙個緩衝區只能儲存一條資訊。即緩衝區只有兩個狀態:有資訊或沒有資訊。

void reader_function ( void );

void writer_function ( void );

char buffer;

int buffer_has_item=0;

pthread_mutex_t mutex;

struct timespec delay;

void main ( void )

void writer_function (void)

/* 開啟互斥鎖*/

pthread_mutex_unlock(&mutex);

pthread_delay_np(&delay); }}

void reader_function(void)

pthread_mutex_unlock(&mutex);

pthread_delay_np(&delay);

}}

程式說明:

這裡宣告了互斥鎖變數mutex,結構pthread_mutex_t為不公開的資料型別,其中包含乙個系統分配的屬性物件。函式pthread_mutex_init用來生成乙個互斥鎖。null引數表明使用預設屬性。如果需要宣告特定屬性的互斥鎖,須呼叫函式pthread_mutexattr_init。函式pthread_mutexattr_setpshared和函式pthread_mutexattr_settype用來設定互斥鎖屬性。前乙個函式設定屬性pshared,它有兩個取值,pthread_process_private和pthread_process_shared。前者用來不同程序中的執行緒同步,後者用於同步本程序的不同執行緒。

在上面的例子中,我們使用的是預設屬性pthread_process_ private。後者用來設定互斥鎖型別,可選的型別有pthread_mutex_normal、pthread_mutex_errorcheck、pthread_mutex_recursive和pthread _mutex_default。它們分別定義了不同的上鎖、解鎖機制,一般情況下,選用最後乙個預設屬性。

pthread_mutex_lock宣告開始用互斥鎖上鎖,此後的**直至呼叫pthread_mutex_unlock為止,均被上鎖,即同一時間只能被乙個執行緒呼叫執行。當乙個執行緒執行到pthread_mutex_lock處時,如果該鎖此時被另乙個執行緒使用,那此執行緒被阻塞,即程式將等待到另乙個執行緒釋放此互斥鎖。在上面的例子中,我們使用了pthread_delay_np函式,讓執行緒睡眠一段時間,就是為了防止乙個執行緒始終佔據此函式。

4.飢餓和死鎖的情形

當乙個互斥量已經被別的執行緒鎖定後,另乙個執行緒呼叫pthread_mutex_lock()函式去鎖定它時,會掛起自己的執行緒等待這個互斥量被解鎖。可能出現以下兩種情況:

「飢餓狀態」:這個互斥量一直沒有被解鎖,等待鎖定它的執行緒將一直被掛著,即它請求某個資源,但永遠得不到它。使用者必須在程式中努力避免這種「飢餓」狀態出現。pthread函式庫不會自動處理這種情況。

「死鎖」:一組執行緒中的所有執行緒都在等待被同組中另外一些執行緒占用的資源,這時,所有執行緒都因等待互斥量而被掛起,它們中的任何乙個都不可能恢復執行,程式無法繼續執行下去。這時就產生了死鎖。pthread函式庫可以跟蹤這種情形,最後乙個執行緒試圖呼叫pthread_mutex_lock()時會失敗,並返回型別為edeadlk的錯誤。

Linux多執行緒程式設計 執行緒互斥鎖

通過下面的練習加深對執行緒的概念的理解,同時明確執行緒的控制。從而進一步了解執行緒的互斥,並學會利用pthread庫。定義乙個用於互斥的互斥鎖 和乙個主函式和兩個子執行緒都能訪問的共享變數,乙個主函式和兩個用來建立子執行緒的子函式 在主函式中定義兩個子執行緒id的變數,初始化互斥鎖,建立對應函式的子...

多執行緒程式設計2 互斥鎖

互斥鎖總結 分類 互斥鎖mutex 條件變數cond 初始化 靜態方式 pthread mutex initializer pthread mutex t mutex pthread mutex initalizer pthread cond initializer pthread cond t c...

多執行緒 互斥鎖

include include include handle mutex null srwlock g lock 改變乙個變數的時候需要鎖定 int num 6400000 在讀期間,值一直在變化,沒有鎖定。dword winapi reada void p i 使用acquiresrwlocksh...