執行緒的互斥鎖

2021-05-22 18:31:58 字數 3822 閱讀 5708

1.執行緒的互斥鎖

1.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. 其他值在以後講解.

1.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, 出錯則返回錯誤編號.

1.3. 死鎖:

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

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

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

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

盡量短時間地占用鎖.

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

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

談了這麼多就讓我舉個實際點的例子來說明以上函式的功能:

#include

#include

#include

#include

#include

pthread_mutex_t mutex = pthread_mutex_initializer;

int lock_var;

time_t end_time;

int sum;

void pthread1(void *arg);

void pthread2(void *arg);

void pthread3(void *arg);

int main(int argc, char *argv)

void pthread1(void *arg)

else

printf("pthread1:pthread1 lock the variable/n");

for(i=0;i<2;i )

if(pthread_mutex_unlock(&mutex)!=0) //unlock

else

printf("pthread1:pthread1 unlock the variable/n");

sleep(1);}}

void pthread2(void *arg)

else

printf("pthread2:pthread2 got lock.the variable is %d/n",lock_var);

if(pthread_mutex_unlock(&mutex)!=0)//unlock

else

printf("pthread2:pthread2 unlock the variable/n");

}sleep(1);}}

void pthread3(void *arg)

else

printf("pthread3:pthread3 got lock.the variable is %d/n",lock_var);

if(pthread_mutex_unlock(&mutex)!=0)

else

printf("pthread3:pthread2 unlock the variable/n");

}sleep(3);

}*/}

**************************************

1.4.遞迴加鎖 的問題

在預設情況下,linux 下的同一執行緒無法對同一互斥鎖進行遞迴加速,否則將發生死鎖。

所謂遞迴加鎖,就是在同一執行緒中試圖對互斥鎖進行兩次或兩次以上的行為

由於在預設情況下,linux 不允許同一執行緒遞迴加鎖,因此在第二次加鎖操作時執行緒將出現死鎖。

清單 1. linux 重複對互斥鎖加鎖例項

// 通過預設條件建鎖

pthread_mutex_t *themutex = new pthread_mutex_t;

pthread_mutexattr_t attr;

pthread_mutexattr_init(&attr);

pthread_mutex_init(themutex,&attr);

pthread_mutexattr_destroy(&attr);

// 遞迴加鎖

pthread_mutex_lock (themutex);

pthread_mutex_lock (themutex);

pthread_mutex_unlock (themutex);

pthread_mutex_unlock (themutex);

在以上**場景中,問題將出現在第二次加鎖操作。由於在預設情況下,linux 不允許同一執行緒遞迴加鎖,因此在第二次加鎖操作時執行緒將出現死鎖。

linux 互斥變數這種奇怪的行為或許對於特定的某些場景會所有用處,但是對於大多數情況下看起來更像是程式的乙個 bug 。畢竟,在同一執行緒中對同一互斥鎖進行遞迴加鎖在尤其是二次開發中經常會需要。

這個問題與互斥鎖的中的預設 recursive 屬性有關。解決問題的方法就是顯式地在互斥變數初始化時將設定起 recursive 屬性。基於此,以上**其實稍作修改就可以很好的執行,只需要在初始化鎖的時候加設定乙個屬性。請看清單 2 。

清單 2. 設定互斥鎖 recursive 屬性例項

pthread_mutexattr_init(&attr);

// 設定 recursive 屬性

pthread_mutexattr_settype(&attr,pthread_mutex_recursive_np);

pthread_mutex_init(themutex,&attr);

因此,建議盡量設定 recursive 屬性以初始化 linux 的互斥鎖,這樣既可以解決同一執行緒遞迴加鎖的問題,又可以避免很多情況下死鎖的發生。這樣做還有乙個額外的好處,就是可以讓 windows 和 linux 下讓鎖的表現統一。

執行緒 互斥鎖

include include include include include 1.靜態初始化,當動態初始化時,遮蔽靜態初始化 pthread mutex t mutex pthread mutex initializer 2.動態初始化 pthread mutex t mutex int lock...

執行緒互斥鎖

執行緒互斥鎖 降低效率,保證資料安全 執行緒 資料共享 修改共享資料,資料不安全 from threading import thread,lock import time n 100 deftask global n temp n time.sleep 0.1 n temp 1 if name m...

執行緒同步與互斥 互斥鎖

在多工作業系統中,同時執行的多個任務可能都需要使用同一種資源。這個過程有點類似於,公司部門裡,我在使用著印表機列印東西的同時 還沒有列印完 別人剛好也在此刻使用印表機列印東西,如果不做任何處理的話,列印出來的東西肯定是錯亂的。下面我們用程式模擬一下這個過程,執行緒一需要列印 hello 執行緒二需要...