天天看點

Linux:多線程-互斥鎖1.互斥鎖作用2.互斥鎖操作3.互斥鎖原理4.互斥鎖執行個體–大媽搶雞蛋

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,就無法獲得鎖。

Linux:多線程-互斥鎖1.互斥鎖作用2.互斥鎖操作3.互斥鎖原理4.互斥鎖執行個體–大媽搶雞蛋

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;
}

           

繼續閱讀