天天看點

線程同步——自旋鎖自旋鎖生産者消費者模型

互斥量的工作原理

如果有多個線程同時通路臨界資源,互斥量保證臨界資源是被串行通路的。某個線程通路臨界資源,線程首先給臨界資源加鎖,加鎖好其他資源無法通路,其他線程隻能等目前線程解鎖後才能使用。

自旋鎖

作業系統提供的API:

pthread_spinlock_t

自旋鎖的工作原理與互斥量一摸一樣,也是在使用前加鎖,使用完解鎖保證串行通路。

自旋鎖也是一種多線程同步的變量,使用了自旋鎖的線程會反複的檢查鎖變量是否可用。如果不可用,就會一直循環的檢查。是以自旋鎖不會讓出CPU,是一種忙等待狀态。是死循環等待鎖被釋放。

自旋鎖的優缺點

  1. 避免了程序或線程的上下文開銷,如果鎖占用時間不長,使用自旋鎖代價很小
  2. 作業系統内部很多地方使用自旋鎖
  3. 不适合在單核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 = 10000000;
    while (times--) {
        pthread_spin_lock(&spin_lock);
        num += 1;
        pthread_spin_unlock(&spin_lock);
    }
}

void *comsumer(void *) {
    int times = 10000000;
    while (times--) {
        pthread_spin_lock(&spin_lock);
        num -= 1;
        pthread_spin_unlock(&spin_lock);
    }
}


int main() {

    pthread_spin_init(&spin_lock, 0);
    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("臨界資源:%d",num)
    return 0;
}

           

不會讓出cpu的demo,讓消費者sleep10秒,生産者的自旋鎖将會循環等待,檢視此時的程序CPU是否為100%。

#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 = 10000000;
    while (times--) {
        pthread_spin_lock(&spin_lock);
        num += 1;
        pthread_spin_unlock(&spin_lock);
    }
}

void *comsumer(void *) {
    int times = 10000000;
    while (times--) {
        pthread_spin_lock(&spin_lock);
        num -= 1;
        sleep(10);
        pthread_spin_unlock(&spin_lock);
    }
}


int main() {

    pthread_spin_init(&spin_lock, 0);
    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("臨界資源: %d\n", num);
    return 0;
}

           

備注:

代碼中使用的是POSIX标準提供的程式設計接口,mac是沒有的,是以在Mac下測試自旋鎖是會出現報錯的。

下圖是Linux下已程序形式測試自旋鎖cpp,可以看到spin_lock所使用的程序接近百分之百,說明自旋鎖在運作的時候并不會讓出CPU。

線程同步——自旋鎖自旋鎖生産者消費者模型

圖檔來源慕課網:《變成必備基礎》

繼續閱讀