1、什么是互斥鎖
????????如果信號量的值最多為 1,那實際上相當于一個共享資源在任意時刻最多只能有一個線程在訪問,這樣的邏輯被稱為“互斥”。這時,有一種更加方便和語義更加準確的工具來滿足這種邏輯,他就是互斥鎖。
????????“鎖”是一種非常形象的說法:就像一個房間只能住一個人一樣,任何人進去之后就把門鎖上了,其他任何人都不能進去,直到進去的那個人重新開開鎖,即釋放了這個鎖資源為止。
????????互斥鎖用于保護線程中某一個共享資源, 該資源在任意一個時刻都只允許有一個線程可以訪問的情況。互斥鎖是專門用于處理線程互斥的一種方式,它有兩種狀態:上鎖狀態、解鎖狀態。
????????例如有多個線程有可能會對某一個鏈表進行刪除、插入的操作。那么任何一個線程想要操作該鏈表前都應該使用互斥鎖來阻塞等待操作的權限(pthread_mutex_lock),當獲得權限后上鎖,阻止其他線程來同時訪問該鏈表造成鏈表的錯亂。當操作結束后使用解鎖函數(pthread_mutex_unlock)把鎖資源釋放出來。
????????特點: 如果互斥鎖處于上鎖狀態,那么再上鎖就會造成阻塞,直到這把鎖解開了之后,才能上鎖。解鎖狀態依然繼續解鎖,不會阻塞。
2、線程互斥鎖API接口
(1)、定義互斥鎖變量
????????數據類型: pthread_mutex_t
pthread_mutex_t m;
(2)、初始化互斥鎖
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *attr);參數:mutex: 未初始化過互斥鎖變量的地址mutexattr:普通屬性,NULL
返回值:成功:0失敗:非0錯誤碼
????????靜態初始化:
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
也就是說,以上這句話等價于:
pthread_mutex_t m;
pthread_mutex_init(&m,NULL);
(3)、線程上鎖
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
參數:mutex:互斥鎖變量的地址
返回值:成功:0失敗:非0錯誤碼
(4)、線程解鎖
#include <pthread.h>
int pthread_mutex_unlock(pthread_mutex_t *mutex);
參數:mutex:互斥鎖變量的地址
返回值:成功:0失敗:非0錯誤碼
(5)、銷毀互斥鎖
#include <pthread.h>
int pthread_mutex_destroy(pthread_mutex_t *mutex);
參數:mutex:互斥鎖變量的地址
返回值:成功:0失敗:非0錯誤碼
3、互斥鎖應用實例
????????互斥鎖使用場景:當我們使用一些臨界資源時,防止多個線程同時訪問,我們可以這么做,在訪問臨界資源前,讓線程先上鎖,然后再訪問資源,訪問完了之后就解鎖,讓別的線程去上鎖。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>int g_val = 0;
//1)定義互斥鎖變量。 -----》數據類型 pthread_mutex_t
pthread_mutex_t mutex;//線程的例程函數,也就是創建線程之后,去執行這個函數
void* routine1(void *arg)
{pthread_mutex_lock(&mutex);//上鎖//寫操作,修改內存空間的值 g_val = 100;int i;for(i=0; i<5; i++){sleep(1); g_val += g_val*i;printf("%d routine1 100 g_val:%d\n",i,g_val); }pthread_mutex_unlock(&mutex);//解鎖
}//線程的例程函數,也就是創建線程之后,去執行這個函數
void* routine2(void *arg)
{pthread_mutex_lock(&mutex);//上鎖//寫操作,修改內存空間的值 g_val = 200;int i;for(i=0; i<5; i++){sleep(1); g_val += g_val*i; printf("routine2 200 g_val:%d\n",g_val); }pthread_mutex_unlock(&mutex);//解鎖
}//線程的例程函數,也就是創建線程之后,去執行這個函數
void* routine3(void *arg)
{pthread_mutex_lock(&mutex);//上鎖int i;//讀操作,此時僅僅只是將這個值打印出來for(i=0; i<5; i++){sleep(1); printf("routine3 g_val:%d\n",g_val); }pthread_mutex_unlock(&mutex);//解鎖
}//線程的例程函數,也就是創建線程之后,去執行這個函數
void* routine4(void *arg)
{pthread_mutex_lock(&mutex);//上鎖int i;//讀操作,此時僅僅只是將這個值打印出來for(i=0; i<5; i++){sleep(1); printf("routine4 g_val:%d\n",g_val); }pthread_mutex_unlock(&mutex);//解鎖
}int main(int argc, char **argv)
{//2)初始化 互斥鎖pthread_mutex_init(&mutex,NULL);// 創建一個新的線程1pthread_t thread1; pthread_create(&thread1,NULL,routine1,NULL); // 創建一個新的線程2pthread_t thread2; pthread_create(&thread2,NULL,routine2,NULL); // 創建一個新的線程3pthread_t thread3; pthread_create(&thread3,NULL,routine3,NULL); // 創建一個新的線程4pthread_t thread4; pthread_create(&thread4,NULL,routine4,NULL); //接合子線程 --阻塞等待子線程退出 回收資源pthread_join(thread1,NULL);pthread_join(thread2,NULL);pthread_join(thread3,NULL);pthread_join(thread4,NULL);//5)銷毀互斥鎖pthread_mutex_destroy(&mutex);return 0;
}
????????如下圖所示為互斥鎖程序的演示結果。從終端打印輸出的信息,可以看到每個線程都是依次有序的排隊進行獲取釋放互斥鎖進行運行的。