計算機操作系統基礎(十一)---線程同步之互斥量

引言

本文爲第十一篇,線程同步之互斥量,在前邊的《計算機操作系統基礎(四)—進程管理之進程同步》中提到了進程同步和線程同步的方法,本篇爲線程同步方法之一—互斥量。建議重新回顧一下《計算機操作系統基礎(四)—進程管理之進程同步》這篇文章,方便理解後邊的幾篇關於線程同步和進程同步的知識

互斥量

在進程同步的那篇文章中有介紹到生產者和消費者模型,該模型中有兩個線程,分別充當生產者和消費者的角色,在併發的情況下,這兩個線程很有可能同時去操作臨界資源,如果同時去操作臨界資源就有可能造成線程同步的問題,互斥量就是解決線程同步的方法之一

互斥量是如何解決這種問題的?

互斥量是保證當某一個線程,比如說線程1在操作臨界資源時,它就可以阻止其它線程訪問臨界資源,這個就是互斥量的工作原理

在前邊的生產者和消費者模型中,引發線程同步的最根本原因其實就是:這兩個線程的指令交叉執行,互斥量可以保證兩個線程的指令不會交叉的執行

其實互斥量的效果也稱爲原子性,互斥量其實就是保證了這些關鍵指令的原子性。原子性就是:

  • 原子性是指一系列操作不可中斷的特性
  • 這一系列操作要麼全部執行完成,要麼全部沒有執行
  • 不存在部分執行,部分未執行的情況

就比如剛纔的生產者的操作,生產者的操作分爲三條指令,根據原子性的特性,這三條指令要麼全部執行完成,要麼全部未執行,不存在說執行了其中的一條或兩條時CPU被搶走了

  • 互斥量是最簡單的線程同步方法
  • 互斥量(互斥鎖),處於兩種狀態之一的變量:解鎖加鎖
  • 兩個狀態可以保證資源訪問的串行(如果說一個資源被加鎖了,也就是這個資源被某一個線程所使用了,另外一個線程如果想使用這個資源的話,只能等待正在使用這個資源的線程釋放資源,另外一個線程纔可以使用這個資源,這樣就保證了資源訪問的串行)

互斥鎖的代碼示例

未使用互斥量

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
$include<vector>

//臨界資源
int num=0;

//生產者
void *producer(void*){
        int times = 100000000;//循環一百萬次
        while(times--){
                num += 1;//每次生產一個產品
        }
}

//消費者
void *comsumer(void*){
        int times = 100000000;
        while(times--){
                num -= 1;//每次消費一個產品
        }
}

int main()
{
        printf("Start in main function.");
        //定義兩個線程
        pthread_t thread1,thread2;
        //一個執行生成者邏輯,一個執行消費者邏輯
        pthread_create(&thread1, NULL, &producer, NULL);
        pthread_create(&thread2, NULL, &comsumer, NULL);
        pthread_join(&thread1, NULL);
        pthread_join(&thread2, NULL);
        //打印臨界資源的值
        printf("Print in main function: num = %d\n", num);
}

運行結果:

雖然生產者和消費者循環的次數都是一樣的,但是num的運行結果卻不是0,這就存在生產者和消費者問題。通過互斥量來解決這個問題

使用互斥量

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
$include<vector>

//初始化互斥量
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;

//臨界資源
int num=0;

//生產者
void *producer(void*){
        int times = 100000000;//循環一百萬次
        while(times--){
                //加鎖
                pthread_mutex_lock(&mutex);
                num += 1;//每次生產一個產品
                //解鎖
               pthread_mutex_unlock(&mutex);
        }
}

//消費者
void *comsumer(void*){
        int times = 100000000;
        while(times--){
                //加鎖
                pthread_mutex_lock(&mutex);
                num -= 1;//每次消費一個產品
                //解鎖
               pthread_mutex_unlock(&mutex);
        }
}

int main()
{
        printf("Start in main function.");
        //定義兩個線程
        pthread_t thread1,thread2;
        //一個執行生成者邏輯,一個執行消費者邏輯
        pthread_create(&thread1, NULL, &producer, NULL);
        pthread_create(&thread2, NULL, &comsumer, NULL);
        pthread_join(&thread1, NULL);
        pthread_join(&thread2, NULL);
        //打印臨界資源的值
        printf("Print in main function: num = %d\n", num);
}

運行結果:

結果是0,說明加互斥量是有作用的。加鎖之後其實會發現代碼的執行時間會變長,這是因爲加鎖會帶來性能的損耗

這就是互斥量的內容,示例是使用C語言進行編寫,各種語言中也都有提供互斥量的API,PHP的互斥量API可參見這裏:https://www.php.net/mutex

在快速變化的技術中尋找不變,纔是一個技術人的核心競爭力。知行合一,理論結合實踐

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