1.互斥鎖作用
在Linux下,多個線程擁有同一個虛拟位址空間,若多個線程對同一塊資料進行操作,可能會産生二義性。造成邏輯混亂。為了保證不發生這些,就需要線程安全。
線程安全的概念:多個線程對同一個臨界資源進行争搶通路,但不會造成資料二義性。
線程安全的實作:就要保證同步與互斥。
同步的實作:條件變量/信号量
互斥的實作:互斥鎖/信号量
互斥鎖為資源引入一個狀态資訊:鎖定/非鎖定
當線程要通路一個臨界資源的時候,需要先檢視這個鎖的狀态資訊
1.若處于開鎖(非鎖定)狀态,就申請到了對臨界資源的通路權,并立即更改鎖的狀态置為鎖定狀态。
2.若處于鎖定狀态,則目前線程阻塞,有R(運作)狀态變成S(休眠)狀态。
2.互斥鎖操作
1.定義互斥鎖變量
pthread_mutex_t 是一個結構體,鎖的類型就是這個。
2.初始化互斥鎖
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
第一個參數傳遞定義的互斥鎖的指針,第二個參數是設定互斥鎖的屬性
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
這種在定義的時候初始化的方式也可以,POSIX定義了一個宏PTHREAD_MUTEX_INITIALIZER來初始化鎖。
3.上鎖
int pthread_mutex_lock(pthread_mutex_t *mutex);
阻塞接口
int pthread_mutex_trylock(pthread_mutex_t *mutex);
非阻塞接口
4.解鎖
int pthread_mutex_unlock(pthread_mutex_t *mutex);
5.銷毀鎖
int pthread_mutex_destroy(pthread_mutex_t *mutex);
3.互斥鎖原理
在pthread_mutex_t結構體中,有一個變量,當它不為0的時候,線程可以繼續執行,否則線程被阻塞。當解鎖的時候,會進行喚醒操作,喚醒因為沒有擷取鎖而阻塞的線程。
點這裡,這個部落格裡具體講了加鎖解鎖的原理
對鎖的狀态判斷和修改鎖的值是一個原子操作,否則可能會導緻,一個線程剛判斷完可以通路資源進行加鎖,另一個線程也正在判斷。那這樣兩個線程可能都會對資源進行通路。
這個原子操作的原理是
1.首先在寄存器裡面設定一個變量0。
2.在對鎖通路的時候會有一個原子操作,将記憶體中鎖中的值和寄存器中的這個0進行交換。
3.再去判斷寄存器中的值,如果是1則可以擷取鎖,如果是0,就無法獲得鎖。
4.互斥鎖執行個體–大媽搶雞蛋
//通過大媽搶雞蛋的例子,體會線程安全的重要性以及認識了解互斥鎖
//每個線程代表一個大媽。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#define MAX_THR 4 //設定建立線程數量
pthread_mutex_t _mutex;//建立互斥鎖變量
int egg = 100;//設定100個雞蛋
void *Dama(void *arg)
{
while(1)
{
pthread_mutex_lock(&_mutex);//先上鎖,讓其他線程阻塞
if(egg > 0)
{
printf("%p搶到了第%d個雞蛋\n",pthread_self(),egg--);
//大媽每次搶一個雞蛋
}
else
{
printf("雞蛋搶完了\n");
pthread_mutex_unlock(&_mutex);//解鎖後退出線程
pthread_exit(NULL);
}
pthread_mutex_unlock(&_mutex);//搶到了進行解鎖
usleep(100);
}
return NULL;
}
int main()
{
int i;
pthread_t tid[MAX_THR];//線程ID
pthread_mutex_init(&_mutex,NULL);//互斥鎖初始化
for(i = 0;i < MAX_THR; i++)
{
int ret = pthread_create(&tid[i],NULL,Dama,NULL);//建立線程
//參數解釋:
//1.儲存目前線程ID
//2.設定線程屬性
//3.設定線程要去執行的函數位址
//4.需要給線程函數中傳遞的參數
if(ret!=0)//判斷線程是否為建立失敗
{
perror("pthread error\n");
return -1;
}
}
for(i = 0;i < MAX_THR; i++)
{
pthread_join(tid[i],NULL);//線程等待
}
pthread_mutex_destroy(&_mutex);//銷毀互斥鎖
return 0;
}