Linux——線程 三 (互斥量)

我們都知道每個線程都有自己獨立的棧空間,自己使用的變量地址也在棧空間內。但是有時候,線程訪問的變量都需要線程共享,這些變量稱爲共享變量,通過數據共享完成線程之間的交互。
我們在進程中瞭解到,多個進程同時訪問一個共享變量的時候,會引發很多問題。所以進程之間需要訪問共享變量的時候,需要互斥。

而對應的,我們線程訪問共享變量,也需要這樣的互斥操作。

我們從一個賣票系統看看,如果沒有使用互斥相關操作,看看會出現什麼樣的結果。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>

int ticket = 4;        //票的總數

void *rout(void *arg)
{
    char *id = (char *)arg;
    while(1)
    {
        if(ticket > 0)
        {
            usleep(1000);
            printf("%s sell ticket:%d \n",id,ticket);
            ticket--;

        }
        else
        {
            break;
        }
    }
}

int main()
{
    pthread_t tid1,tid2,tid3;

    pthread_create(&tid1,NULL,rout,"thread1");
    pthread_create(&tid2,NULL,rout,"thread2");
    pthread_create(&tid3,NULL,rout,"thread3");

    pthread_join(tid1,NULL);
    pthread_join(tid1,NULL);
    pthread_join(tid1,NULL);

    return 0;
}

看一下運行結果:
這裏寫圖片描述

很明顯,運行的結果顯示,不符合我們預期的效果。

我們的票數爲4張,但是可以看到最後thread2 都賣到了 -1 張票了,這是不符合實際的問題的結果。

由於ticket 是全局變量,每個線程都可以訪問到它,每個線程都在可能切換到運行狀態,在線程函數裏,出現了usleep() 等待,這時候系統可能切換到另一個進程中,又賣出了一張票,等該線程的運行時間到了後,再返回原來線程的時候,還繼續對票數減一了。這就導致了程序的不符合實際性。

我們應該怎麼解決這個問題呢?
1.代碼必須要有互斥行爲,當代碼進入臨界區執行時,不允許其他線程進入該臨界區。
2.如果多個線程同時要求執行臨界區的代碼,並且臨界區沒有線程在執行時,那麼只允許一個線程進入該臨界區。
3.如果線程不在臨界區中執行,那麼該線程不能阻止其他線程進入到臨界區。

這就是給臨界區上了一把鎖。 Linux上提供的這邊鎖叫做互斥量。

我們還可以這樣定義互斥量:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER ;

這樣定義的互斥量不需要進行初始化和刪除,系統會自動的初始化和刪除。

互斥量:
1.定義一個互斥量  pthread_mutex_t mutex

2.初始化信號量 pthread_mutex_init(&mutex,NULL);  //初始化成1

3.上鎖 pthread_mutex_lock(&mutex);
        1->0,返回
        0   ,等待


4.銷燬 pthread_mutex_destroy(&mutex); 

這樣我們改進一下我們的買票系統:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>

int ticket = 4;

//pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

pthread_mutex_t mutex;     //定義互斥量

void *rout(void *arg)
{
    char *id = (char *)arg;
    while(1)
    {
        pthread_mutex_lock(&mutex);                     //上鎖
        if(ticket > 0)
        {
            usleep(1000);
            printf("%s sell ticket:%d \n",id,ticket);
            ticket--;
            pthread_mutex_unlock(&mutex);            //解鎖
        }
        else
        {
            pthread_mutex_unlock(&mutex);            //解鎖
            break;
        }
    }
}

int main()
{
    pthread_t tid1,tid2,tid3;
    pthread_mutex_init(&mutex,NULL);            //初始化互斥量

    pthread_create(&tid1,NULL,rout,"thread1");
    pthread_create(&tid2,NULL,rout,"thread2");
    pthread_create(&tid3,NULL,rout,"thread3");

    pthread_join(tid1,NULL);
    pthread_join(tid1,NULL);
    pthread_join(tid1,NULL);

    pthread_mutex_destroy(&mutex);                //銷燬互斥量

    return 0;
}

運行結果圖:
這裏寫圖片描述

添加了互斥量過後,該系統的買票結果與我們的預想效果一樣。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章