Linux C 中4種互斥鎖簡述

2021-09-06 15:44:07 字數 3495 閱讀 6589

1.普通鎖 (pthread_mutex_normal)

互斥鎖預設型別。當乙個執行緒對乙個普通鎖加鎖以後,其餘請求該鎖的執行緒將形成乙個等待佇列,並在該鎖解鎖後按照優先順序獲得它,這種鎖型別保證了資源分配的公平性。乙個執行緒如果對乙個已經加鎖的普通鎖再次加鎖,將引發死鎖;

對乙個已經被其他執行緒加鎖的普通鎖解鎖,或者對乙個已經解鎖的普通鎖再次解鎖,將導致不可預期的後果。

2.檢錯鎖(pthread_mutex_errorcheck)

乙個執行緒如果對乙個已經加鎖的檢錯鎖再次加鎖,則加鎖操作返回edeadlk;

對乙個已經被其他執行緒加鎖的檢錯鎖解鎖或者對乙個已經解鎖的檢錯鎖再次解鎖,則解鎖操作返回eperm;

3.巢狀鎖(pthread_mutex_recursive)

該鎖允許乙個執行緒在釋放鎖之前多次對它加鎖而不發生死鎖;

其他執行緒要獲得這個鎖,則當前鎖的擁有者必須執行多次解鎖操作;

對乙個已經被其他執行緒加鎖的巢狀鎖解鎖,或者對乙個已經解鎖的巢狀鎖再次解鎖,則解鎖操作返回eperm

4.預設鎖(pthread_mutex_ default)

乙個執行緒如果對乙個已經加鎖的預設鎖再次加鎖,或者雖乙個已經被其他執行緒加鎖的預設鎖解鎖,或者對乙個解鎖的預設鎖解鎖,將導致不可預期的後果;

這種鎖實現的時候可能被對映成上述三種鎖之一;

1.不同執行緒申請普通鎖,將按照順序依次申請鎖並加鎖

#include #include pthread_mutex_t mutex1 = pthread_mutex_initializer;

int count = 0;

void * thread_func_one(void *arg)

return null;

}void * thread_func_two(void *arg)

return null;

}int main ( int argc, char **argv)

if( 0!=pthread_create( &thread_one, null, thread_func_two,null))

pthread_join(thread_one, null);

pthread_join(thread_two,null);

return 0;

}

2.乙個執行緒對乙個普通鎖兩次加鎖將導致死鎖

#include #include pthread_mutex_t mutex1 = pthread_mutex_initializer;

int count = 0;

void * thread_func_one(void *arg)

return null;

}void * thread_func_two(void *arg)

return null;

}int main ( int argc, char **argv)

if( 0!=pthread_create( &thread_one, null, thread_func_two,null))

pthread_join(thread_one, null);

pthread_join(thread_two,null);

return 0;

}

3.按不同順序訪問互斥鎖導致死鎖

#include #include #include int a = 0;

int b = 0;

pthread_mutex_t mutexa;

pthread_mutex_t mutexb;

void* another(void* arg)

int main ( int argc, char **argv)

分析:

主線程試圖先占有互斥鎖mutex_a,且又申請互斥鎖mutex_b,並在兩個互斥鎖的保護下,操作變數a和b,最後才一起釋放兩個互斥鎖;

與此同時,子執行緒按照相反的順序來申請互斥鎖mutex_a和mutex_b,並在兩個鎖的保護下操作變數a和b。

我們用sleep(5)為了模擬連續兩次呼叫pthread_mutex_lock之間的時間差,以確保**中的兩個執行緒各自先占有乙個互斥鎖(主線程占有mutex_a,子執行緒占有mutex_b),然後等待另外乙個互斥鎖(主線程等待mutex_b,子執行緒等到mutex_a)

兩個執行緒將僵持住,誰都不能繼續往下執行,從而形成死鎖;

如果**中不加sleep函式,也許這段**能夠執行成功,但是會為程式留下乙個潛在哦bug.

4.在多執行緒程式中呼叫fork導致死鎖

#include #include #include #include #include pthread_mutex_t mutex;

void* another(void* arg)

int main ( int argc, char **argv)

else if( pid == 0 )

else

pthread_join( id, null );

pthread_mutex_destroy( &mutex );

return 0;

}

分析:

子程序只擁有乙個執行執行緒,它是呼叫fork的那個執行緒的完整複製。

子程序中將自動繼承父程序中的互斥鎖的狀態,也就是說,父程序中已經被加鎖的互斥鎖在子程序中也是鎖住的,這將引發下面問題:

子程序可能不清楚從父程序繼承而來的互斥鎖的具體狀態(是加鎖狀態還是解鎖狀態);這個互斥鎖已經加鎖了,但不是由呼叫fork函式的那個執行緒鎖住的,而是由其他執行緒鎖住的。由於主程序和子程序有兩份不同的記憶體,即使主程序中的子執行緒釋放掉鎖,也不會影響子程序中的鎖的狀態,這種情況就是上面**情況,導致死鎖;

針對上面**情況死鎖,pthread提供了乙個專門函式pthread_atfork,以確保fork呼叫後父程序和子程序都擁有乙個清楚的鎖狀態:int pthread_arfork(void (*prepare)(void), void (*parent)(void),void (*child)(void)) ;

上面該函式將建立3個fork控制代碼來幫助我們清理互斥鎖的狀態。prepare控制代碼將在fork呼叫建立出子程序之前被執行,它用來鎖住所有父程序中的互斥鎖;parent控制代碼這是fork呼叫建立出子程序之後,而fork返回之前,在父程序中被執行,它的作用:釋放所有在prepare控制代碼中被鎖住的互斥鎖;child控制代碼是fork返回之前,在子程序中被執行,和parent控制代碼一樣,child控制代碼也是用於釋放所有在prepare控制代碼中被鎖住的互斥鎖。該函式成功返回0,失敗返回錯誤**。

通過將pthread_atfork代替fork避免死鎖

void prepare()

void infork()

pthread_atfork( prepare, infork, infork );

linux c 多執行緒互斥鎖

beers.c include include include include include include int beers 2000000 建立互斥鎖,互斥鎖對所有可能發生衝突的執行緒可見,是乙個全域性變數.pthread mutex initializer實際上是乙個巨集,當編譯器看到它,...

linux c使用互斥鎖實現同步

1.需要使用到的庫pthread.h 2.需要使用到的函式有pthread mutex init,pthread mutex destory,pthread mutex lock,pthread unlock,3.需要保護的資料結構為 typedef struct cnt sum cnt sum兩個...

簡述python多執行緒中的互斥鎖

在程式設計 中,為了 保證共享資料 操作的完整性,引入了 互斥鎖的概念。每個 物件都對應於乙個可稱為 互斥鎖 的標記,這個標記用來保證在任一時刻,只能有乙個 執行緒訪問該 物件。在python中由於多執行緒的存在,並且對全域性變數作用時有可能產生全域性變數紊亂問題,所以也加入了同步和互斥等方法,但是...