自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

CPU瘋狂打轉(zhuǎn)背后的故事:一篇文章教你理解自旋鎖!

開發(fā) 前端
自旋鎖其實(shí)就是一種“死磕到底”的鎖,適用于那種“等一下就能用”的情況。現(xiàn)實(shí)生活中也有很多類似的場景,比如公共健身器材的排隊(duì),等電梯,等等。理解了“自旋”其實(shí)就是一種“忙等”方式,才能更好地應(yīng)對面試中的各種多線程問題。

前言

想象一下,你去上班,發(fā)現(xiàn)電梯壞了。站在電梯口等著,心里想著“它馬上就會好吧?”。于是,你開始重復(fù)按著電梯按鈕,一分鐘又一分鐘地等著,心里甚至有點(diǎn)煩躁。這種狀態(tài)就像“自旋”一樣——你站在原地,做著重復(fù)的動作,不走開,等著電梯修好。

在計(jì)算機(jī)世界里,“自旋”指的就是這種不斷重復(fù)、原地等待的狀態(tài)。今天,我們就來聊聊“自旋鎖”是什么,為啥要用它,它又是怎么工作的。

一、自旋是什么?

在多線程編程中,如果多個(gè)線程要訪問同一個(gè)資源,就必須協(xié)調(diào)好,不能一起上去“搶”。為了避免數(shù)據(jù)混亂,我們常用鎖機(jī)制來管理這些資源,而“自旋鎖”就是其中一種特殊的鎖。

那么,什么是“自旋”呢?

自旋的本質(zhì),就是一個(gè)“等”的動作。某個(gè)線程在等待資源解鎖時(shí),不去睡眠、不去做別的任務(wù),而是持續(xù)檢查——“資源解鎖了嗎?解鎖了嗎?”。這種重復(fù)檢查、原地等待的動作,就是“自旋”。當(dāng)資源解鎖時(shí),它可以立刻進(jìn)入使用,而不用浪費(fèi)時(shí)間重新“醒過來”。

二、形象化理解:小區(qū)公共健身器材

想象你住的小區(qū),有一套公共健身器材,比如單杠。周末你想去玩單杠,但到了發(fā)現(xiàn)前面有人在用。你很想盡快上去,但也不想離開,萬一人家馬上玩完了呢?于是,你站在一旁,隨時(shí)準(zhǔn)備上場。

這時(shí),有兩種選擇:

  • 選項(xiàng)A: 站在旁邊等,眼睛緊盯著單杠,直到前面那人下來,立馬沖上去!這就是“自旋鎖”的方式。
  • 選項(xiàng)B: 先去跑個(gè)圈、做點(diǎn)別的,等回來再看前面的人走沒走,這種叫“休眠鎖”,類似于互斥鎖。

在選項(xiàng)A中,你會一直“自旋”等待著機(jī)會,但這種方式只有在“前面那個(gè)人快要結(jié)束”的情況下才有意義,否則一直站著等,既浪費(fèi)時(shí)間又累。所以,自旋鎖適用于等待時(shí)間短、資源即將釋放的場景。

三、 自旋鎖和互斥鎖的區(qū)別是什么?

自旋鎖和互斥鎖(Mutex)都能保證同一時(shí)間只有一個(gè)線程能訪問共享資源,但它們的區(qū)別在于:

  • 互斥鎖:如果線程沒有拿到鎖,它會進(jìn)入休眠狀態(tài),等鎖釋放后再喚醒,可能會產(chǎn)生一些“調(diào)度開銷”。
  • 自旋鎖:如果線程沒有拿到鎖,它不會休眠,而是“原地自旋”等待鎖的釋放,減少了調(diào)度的開銷。

因此,自旋鎖 特別適合那種“等待時(shí)間很短”的情況,比如一段代碼塊執(zhí)行非??欤€程只需稍微等一下就能拿到鎖,這時(shí)自旋鎖就能顯著減少開銷。

四、先了解自旋鎖的基本接口

在 Linux 的pthread庫中,我們可以用pthread_spin_init來初始化一個(gè)自旋鎖,用pthread_spin_lock和pthread_spin_unlock來上鎖和解鎖。

注意,自旋鎖與互斥鎖不同,自旋鎖不允許等待的線程進(jìn)入“休眠”,而是不斷檢查鎖是否可用。

pthread_spinlock_t spin;
pthread_spin_init(&spin, 0);  // 初始化自旋鎖

pthread_spin_lock(&spin);     // 自旋等待獲取鎖
// 訪問共享資源
pthread_spin_unlock(&spin);   // 釋放鎖

pthread_spin_destroy(&spin);  // 銷毀自旋鎖

五、實(shí)際代碼示例

在 Linux 內(nèi)核或多線程編程中,自旋鎖是一種重要的同步機(jī)制。以下是一個(gè)簡單的自旋鎖代碼示例,用于模擬多線程的共享資源訪問:

#include <pthread.h>
#include <stdio.h>

int shared_data = 0;
pthread_spinlock_t spinlock;

void* increment_data(void* arg) {
    pthread_spin_lock(&spinlock);  // 加鎖,開始“自旋”
    shared_data++;
    printf("Thread %d: shared_data = %d\n", *(int*)arg, shared_data);
    pthread_spin_unlock(&spinlock);  // 解鎖,停止“自旋”
    return NULL;
}

int main() {
    pthread_t threads[5];
    pthread_spin_init(&spinlock, 0);  // 初始化自旋鎖

    int thread_ids[5] = {0, 1, 2, 3, 4};
    for (int i = 0; i < 5; i++) {
        pthread_create(&threads[i], NULL, increment_data, &thread_ids[i]);
    }

    for (int i = 0; i < 5; i++) {
        pthread_join(threads[i], NULL);
    }

    pthread_spin_destroy(&spinlock);  // 銷毀自旋鎖
    return 0;
}

在上面的代碼中,每個(gè)線程都嘗試去訪問shared_data這個(gè)共享變量。通過自旋鎖機(jī)制,線程會一直“等”到其他線程釋放鎖,確保每次只有一個(gè)線程可以修改shared_data,避免了數(shù)據(jù)混亂。

六、 自旋鎖的應(yīng)用場景:什么時(shí)候用自旋鎖?

自旋鎖的特點(diǎn),就是“急”,不愿意浪費(fèi)時(shí)間等待。它適合那些等待時(shí)間短、需要快速響應(yīng)的情況,常見的場景有這些:

  1. 小任務(wù):比如你只是要讀取或修改一個(gè)小變量,操作很快完成,沒必要讓線程進(jìn)入休眠再醒來,這種情況下自旋鎖很合適。它能讓線程馬上完成任務(wù),釋放鎖,保持流程流暢。
  2. 多核系統(tǒng):在多核系統(tǒng)里,自旋鎖更有優(yōu)勢,因?yàn)橐粋€(gè)核在“忙等”時(shí),其他核還能正常工作。這樣線程不被阻塞,能有效提高整個(gè)系統(tǒng)的運(yùn)行效率。
  3. 操作系統(tǒng)內(nèi)核的關(guān)鍵任務(wù):在操作系統(tǒng)內(nèi)核中,很多任務(wù)要求速度快、等待時(shí)間短,自旋鎖的特性就很適用。自旋鎖能確保關(guān)鍵資源在被短時(shí)間鎖定時(shí),不產(chǎn)生過多的調(diào)度開銷。

總之,自旋鎖 適合那些“等一小會兒就能用到”的情況,如果任務(wù)很簡單、耗時(shí)很短,用它就能提高效率。但如果任務(wù)復(fù)雜、需要長時(shí)間鎖定資源,還是換成別的鎖更靠譜(比如互斥鎖)。

七、自旋鎖的陷阱:CPU高占用

自旋鎖的主要風(fēng)險(xiǎn)是會導(dǎo)致 CPU 高占用。假設(shè)一個(gè)線程長時(shí)間持有鎖,其他線程就會一直自旋等待,浪費(fèi) CPU。

解決方法:設(shè)置最大等待次數(shù)

可以給自旋鎖設(shè)置一個(gè)“最多等幾次”的限制。比如,如果等了5次還沒拿到鎖,那就放棄,不再繼續(xù)浪費(fèi)CPU。這種方式在 Linux 的 pthread_spin_trylock 實(shí)現(xiàn)中經(jīng)常被使用。

簡單代碼示例

以下是一個(gè)帶限制的自旋鎖示例:

int try_spinlock_with_limit(pthread_spinlock_t *lock, int max_attempts) {
    int attempt = 0;
    while (attempt < max_attempts) {
        if (pthread_spin_trylock(lock) == 0) {  // 成功拿到鎖
            return 0;
        }
        attempt++;
    }
    return -1;  // 達(dá)到最大次數(shù),放棄
}

這里每次加鎖最多等 5 次,沒拿到鎖就直接放棄。這樣可以避免CPU一直空耗在等待上,提升效率。

八、自旋鎖的優(yōu)缺點(diǎn)

優(yōu)點(diǎn)

  1. 快速響應(yīng):自旋鎖不涉及上下文切換的開銷,在資源會快速釋放的情況下,自旋等待更節(jié)省時(shí)間。
  2. 適合多核處理:在多核系統(tǒng)中,一個(gè)核的線程“自旋”等待時(shí),另一個(gè)核的線程可以繼續(xù)工作,實(shí)現(xiàn)更好的并行性。

缺點(diǎn)

  1. CPU占用高:自旋鎖的線程不會釋放CPU資源,所以等待時(shí)間長時(shí)會浪費(fèi)CPU。
  2. 只能短期等待:如果鎖被長期占用,自旋鎖會導(dǎo)致資源浪費(fèi),還不如直接睡眠。這個(gè)時(shí)候使用互斥鎖可能會更好。

九、C++ 如何實(shí)現(xiàn)自旋鎖?

在 C/C++ 編程中, 只有 Linuxpthread 庫提供了自旋鎖相關(guān)接口,而在 C++ 標(biāo)準(zhǔn)庫中,并沒有直接提供自旋鎖(spinlock)的接口。不過,你可以使用 std::atomic_flag 來實(shí)現(xiàn)一個(gè)簡單的自旋鎖,因?yàn)?std::atomic_flag 是一個(gè)輕量級的原子布爾標(biāo)志,非常適合構(gòu)建自旋鎖。

下面是一個(gè)使用 std::atomic_flag 實(shí)現(xiàn)自旋鎖的示例:

#include <atomic>
#include <thread>

class SpinLock {
private:
    std::atomic_flag flag = ATOMIC_FLAG_INIT;

public:
    void lock() {
        while (flag.test_and_set(std::memory_order_acquire)) {
            // 自旋等待,直到獲得鎖
        }
    }

    void unlock() {
        flag.clear(std::memory_order_release);
    }
};

使用方法:

SpinLock spinlock;

void critical_section() {
    spinlock.lock();
    // 臨界區(qū)代碼
    spinlock.unlock();
}

說明:

  • 自旋鎖的實(shí)現(xiàn):lock() 方法中使用了 test_and_set,它會不斷嘗試將 flag 設(shè)置為 true,直到成功獲取鎖。如果鎖已經(jīng)被其他線程占用,它會進(jìn)入自旋等待狀態(tài),持續(xù)嘗試獲取鎖。
  • 釋放鎖:unlock() 方法通過 clear 將 flag 設(shè)為 false,釋放鎖,使其他線程可以進(jìn)入臨界區(qū)。

十、總結(jié)

自旋鎖其實(shí)就是一種“死磕到底”的鎖,適用于那種“等一下就能用”的情況?,F(xiàn)實(shí)生活中也有很多類似的場景,比如公共健身器材的排隊(duì),等電梯,等等。理解了“自旋”其實(shí)就是一種“忙等”方式,才能更好地應(yīng)對面試中的各種多線程問題。

希望這篇文章讓你對“自旋鎖”有了更全面、清晰的理解。下次面試時(shí),再遇到這個(gè)面試題,你一定能從容應(yīng)答,既講清原理,又能結(jié)合實(shí)際應(yīng)用,輕松拿下!

責(zé)任編輯:武曉燕 來源: 跟著小康學(xué)編程
相關(guān)推薦

2017-09-05 08:52:37

Git程序員命令

2022-10-08 15:07:06

ChatOps運(yùn)維

2019-07-15 07:58:10

前端開發(fā)技術(shù)

2021-07-13 11:37:47

cpu架構(gòu)Linux

2021-03-08 09:15:46

日志Filebeat運(yùn)維

2020-03-31 08:37:31

遞歸單鏈表反轉(zhuǎn)

2024-05-17 10:05:06

Java機(jī)制應(yīng)用

2020-10-09 08:15:11

JsBridge

2020-12-29 05:35:43

FlinkSQL排序

2021-04-07 13:28:21

函數(shù)程序員異步

2022-02-21 09:44:45

Git開源分布式

2023-05-12 08:19:12

Netty程序框架

2021-06-30 00:20:12

Hangfire.NET平臺

2019-04-17 15:16:00

Sparkshuffle算法

2024-06-25 08:18:55

2021-04-09 08:40:51

網(wǎng)絡(luò)保險(xiǎn)網(wǎng)絡(luò)安全網(wǎng)絡(luò)風(fēng)險(xiǎn)

2018-05-31 09:44:01

微服務(wù)架構(gòu)數(shù)據(jù)

2011-07-12 13:35:04

程序員

2019-10-17 19:15:22

jQueryJavaScript前端

2021-05-15 09:18:04

Python進(jìn)程
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號