計算機操作系統基礎(十二)---線程同步之自旋鎖

引言

本文爲第十二篇,線程同步之自旋鎖,在上一篇文章介紹了互斥量,通過互斥量解決線程同步的問題。本文是另一個解決線程同步的方法—自旋鎖

自旋鎖

自旋鎖的工作原理跟互斥量的工作原理其實是一模一樣的,它也是在訪問臨界資源之前加一個鎖,完成之後再將鎖給釋放掉。但是互斥量和自旋鎖還是有一點區別的

  • 自旋鎖也是一種多線程同步的變量
  • 使用了自旋鎖的線程會反覆檢查鎖變量是否可用,如果不可用就會循環反覆的檢查
  • 因此自旋鎖不會讓出CPU,是一種忙等待狀態

因此自旋鎖其實就是:死循環等待鎖被釋放

自旋鎖好處

  • 自旋鎖避免了進程或線程上下文切換的開銷(如果這個鎖佔用的時間不是很長,這個代價還是很小的)
  • 操作系統內部很多地方都是使用自旋鎖,而不是互斥量
  • 自旋鎖不適合在單核CPU使用(因爲自旋鎖在等待的時候並不會釋放CPU,如果在單核CPU使用的話會引起其它的進程或線程無法執行)

自旋鎖和互斥量(鎖)的比較

  • 自旋鎖是一種非阻塞鎖,也就是說,如果某線程需要獲取自旋鎖,但該鎖已經被其他線程佔用時,該線程不會被掛起,而是在不斷的消耗CPU的時間,不停的試圖獲取自旋鎖
  • 互斥量是阻塞鎖,當某線程無法獲取互斥量時,該線程會被直接掛起,該線程不再消耗CPU時間,當其他線程釋放互斥量後,操作系統會激活那個被掛起的線程,讓其投入運行

兩種鎖適用的場景

  • 如果是多核處理器,如果預計線程等待鎖的時間很短,短到比線程兩次上下文切換時間要少的情況下,使用自旋鎖是划算的
  • 如果是多核處理器,如果預計線程等待鎖的時間較長,至少比兩次線程上下文切換的時間要長,建議使用互斥量
  • 如果是單核處理器,一般建議不要使用自旋鎖。因爲,在同一時間只有一個線程是處在運行狀態,那如果運行線程發現無法獲取鎖,只能等待解鎖,但因爲自身不掛起,所以那個獲取到鎖的線程沒有辦法進入運行狀態,只能等到運行線程把操作系統分給它的時間片用完,纔能有機會被調度。這種情況下使用自旋鎖的代價很高

建議:如果加鎖的代碼經常被調用,但競爭情況很少發生時,應該優先考慮使用自旋鎖,自旋鎖的開銷比較小,互斥量的開銷較大

自旋鎖的代碼示例

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

//自旋鎖定義
pthread_spinlock_t spin_lock;

//臨界資源
int num=0;

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

//消費者
void *consumer(void*){
        int times = 100000000;
        while(times--){
              //加自旋鎖
              pthread_spin_lock(&spin_lock);
                num -= 1;//每次消費一個產品
                //解鎖
            pthread_spin_unlock(&spin_lock);
        }
}

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

執行結果

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

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