互斥鎖和條件變數

2021-09-30 13:29:27 字數 4221 閱讀 6625



一、互斥鎖

互斥量從本質上說就是一把鎖, 提供對共享資源的保護訪問。

1. 初始化:

在linux下, 執行緒的互斥量資料型別是pthread_mutex_t. 在使用前, 要對它進行初始化:

對於靜態分配的互斥量, 可以把它設定為pthread_mutex_initializer, 或者呼叫pthread_mutex_init.

對於動態分配的互斥量, 在申請記憶體(malloc)之後, 通過pthread_mutex_init進行初始化, 並且在釋放記憶體(free)前需要呼叫pthread_mutex_destroy.

原型:int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restric attr);

int pthread_mutex_destroy(pthread_mutex_t *mutex);

標頭檔案:

返回值: 成功則返回0, 出錯則返回錯誤編號.

說明: 如果使用預設的屬性初始化互斥量, 只需把attr設為null. 其他值在以後講解。

2. 互斥操作:

對共享資源的訪問, 要對互斥量進行加鎖, 如果互斥量已經上了鎖, 呼叫執行緒會阻塞, 直到互斥量被解鎖. 在完成了對共享資源的訪問後, 要對互斥量進行解鎖。

首先說一下加鎖函式:

標頭檔案:

原型:int pthread_mutex_lock(pthread_mutex_t *mutex);

int pthread_mutex_trylock(pthread_mutex_t *mutex);

返回值: 成功則返回0, 出錯則返回錯誤編號.

說明: 具體說一下trylock函式, 這個函式是非阻塞呼叫模式, 也就是說, 如果互斥量沒被鎖住, trylock函式將把互斥量加鎖, 並獲得對共享資源的訪問許可權; 如果互斥量被鎖住了, trylock函式將不會阻塞等待而直接返回ebusy, 表示共享資源處於忙狀態。

再說一下解所函式:

標頭檔案:

原型: int pthread_mutex_unlock(pthread_mutex_t *mutex);

返回值: 成功則返回0, 出錯則返回錯誤編號.

3. 死鎖:

死鎖主要發生在有多個依賴鎖存在時, 會在乙個執行緒試圖以與另乙個執行緒相反順序鎖住互斥量時發生. 如何避免死鎖是使用互斥量應該格外注意的東西。

總體來講, 有幾個不成文的基本原則:

對共享資源操作前一定要獲得鎖。

完成操作以後一定要釋放鎖。

盡量短時間地占用鎖。

如果有多鎖, 如獲得順序是abc連環扣, 釋放順序也應該是abc。

執行緒錯誤返回時應該釋放它所獲得的鎖。

二、條件變數

這裡主要說說

pthread_cond_wait()的用法,在下面有說明。

條件變數是利用執行緒間共享的全域性變數進行同步的一種機制,主要包括兩個動作:一

個執行緒等待"條件變數的條件成立"而掛起;另乙個執行緒使"條件成立"(給出條件成立訊號)。為了防止競爭,條件變數的使用總是和乙個互斥鎖結合在一起。  

1.   建立和登出  

條件變數和互斥鎖一樣,都有靜態動態兩種建立方式,靜態方式使用pthread_cond_initializer常量,如下:    

pthread_cond_t   cond=pthread_cond_initializer    

動態方式呼叫pthread_cond_init()函式,api定義如下:    

int   pthread_cond_init(pthread_cond_t   *cond,   pthread_condattr_t   *cond_attr)    

儘管posix標準中為條件變數定義了屬性,但在linuxthreads中沒有實現,因此cond_attr值通常為null,且被忽略。  

登出乙個條件變數需要呼叫pthread_cond_destroy(),只有在沒有執行緒在該條件變數上等待的時候才能登出這個條件變數,否則返回ebusy。因為linux實現的條件變數沒有分配什麼資源,所以登出動作只包括檢查是否有等待執行緒。api定義如下:    

int   pthread_cond_destroy(pthread_cond_t   *cond)

2.   等待和激發  

int   pthread_cond_wait(pthread_cond_t   *cond,   pthread_mutex_t   *mutex)

執行pthread_cond_wait()時

自動解鎖互斥量(如同執行了 pthread_unlock_mutex),並等待條件變數觸發。這時執行緒掛起,不占用 cpu 時間,直到條件變數被觸發。

因此,全過程可以描述為:

(1)pthread_mutex_lock()上鎖,

(2)pthread_cond_wait()等待,等待過程分解為為:解鎖--條件滿足--加鎖

(3)pthread_mutex_unlock()解鎖。

激發條件有兩種形式,pthread_cond_signal()啟用乙個等待該條件的執行緒,存在多個等待執行緒時按入隊順序啟用其中乙個;而pthread_cond_broadcast()則啟用所有等待執行緒。 兩者 如果沒有等待的執行緒,則什麼也不做。

下面是一段經典**:

#include#include#include#include#includestatic pthread_mutex_t mtx = pthread_mutex_initializer;

static pthread_cond_t cond = pthread_cond_initializer;

struct node

*head = null;/*[thread_func]*/

/*釋放節點記憶體*/

static void cleanup_handler(void*arg)

*((struct node **)arg) = null;

(void)pthread_mutex_unlock(&mtx);

}static void* thread_func(void*arg)

//pthread_cond_wait會先解除之前的pthread_mutex_lock鎖定的mtx,

//然後阻塞在等待佇列裡休眠,直到再次被喚醒

//(大多數情況下是等待的條件成立而被喚醒,喚醒後,

//該程序會先鎖定先pthread_mutex_lock(&mtx);,

//再讀取資源用這個流程是比較清楚的

/*block-->unlock-->wait()return-->lock*/

p = head;

head = head->n_next;

printf("got %d from front of queue\n",p->n_number);

free(p);

}pthread_mutex_unlock(&mtx);//臨界區資料操作完畢,釋放互斥鎖

}pthread_cleanup_pop(0);

return 0;

}int main(void)

p=(struct node*)malloc(sizeof(struct node));

p->n_number=i;

pthread_mutex_lock(&mtx);//需要操作head這個臨界資源,先加鎖,

p->n_next=head;

head=p;

pthread_mutex_unlock(&mtx);//解鎖

printf("thread1 wanna end the cancel thread2.\n");

pthread_cancel(tid);

//關於pthread_cancel,有一點額外的說明,它是從外部終止子執行緒,

//子執行緒會在最近的取消點,退出執行緒,而在我們的**裡,最近的

//取消點肯定就是pthread_cond_wait()了。

pthread_join(tid,null);

printf("all done--exiting\n");

return 0;

}

互斥鎖和條件變數

互斥瑣 定義 指代相互排斥,最基本的同步形式。用於保護臨界區,以保證任何時刻只有乙個執行緒或乙個程序在執行其中的 上鎖 pthread mutex lock 臨界區解鎖 pthread mutex unlock 條件變數 定義 用於等待訊號,同步的另一種手段。每乙個條件變數總有乙個互斥瑣與之關聯。等...

互斥鎖和條件變數

mutex體現的是一種競爭,我離開了,通知你進來。cond體現的是一種協作,我準備好了,通知你開始吧。互斥鎖乙個明顯的缺點是它只有兩種狀態 鎖定和非鎖定。而條件變數通過允許執行緒阻塞和等待另乙個執行緒傳送訊號的方法彌補了互斥鎖的不足,它常和互斥鎖一起配合使用。使用時,條件變數被用來阻塞乙個執行緒,當...

互斥鎖和條件變數

條件變數 執行緒最大的特點就是資源的共享性,然而資源共享中的同步問題是多執行緒程式設計的難點。互斥鎖通過鎖機制來實現執行緒間的同步。使用互斥鎖前必須進行初始化操作。初始化有兩種方式 一種是靜態賦值法,將將巨集結構常量pthread mutex initializer賦給互斥鎖,操作語句如下 pthr...