深入探究C/C++中互斥量(鎖)的實(shí)現(xiàn)原理
互斥量的概念
互斥量(mutex)是一種同步原語(yǔ),用于保護(hù)多個(gè)線(xiàn)程同時(shí)訪(fǎng)問(wèn)共享數(shù)據(jù)?;コ饬刻峁┆?dú)占的、非遞歸的所有權(quán)語(yǔ)義:一個(gè)線(xiàn)程從成功調(diào)用lock或try_lock開(kāi)始,到調(diào)用unlock結(jié)束,都擁有互斥量。
何為原子性操作
程序的原子性指:整個(gè)程序中的所有操作,要么全部完成,要么全部不完成,不可能停滯在中間某個(gè)環(huán)節(jié)。
原子性在一個(gè)操作是不可中斷的,要么全部執(zhí)行成功要么全部執(zhí)行失敗,有著 “同生共死” 的感覺(jué)。在多個(gè)線(xiàn)程一起執(zhí)行的時(shí)候,一個(gè)操作一旦開(kāi)始,就不會(huì)被其他線(xiàn)程所干擾
如果要保證原子性,必須符合以下兩條規(guī)則:
運(yùn)算結(jié)果并不依賴(lài)于變量的當(dāng)前值,或者能夠確保只有一個(gè)線(xiàn)程修改變量的值。
變量不需要與其他的狀態(tài)變量共同參與不變約束。
原理探究
首先給出一段加鎖場(chǎng)景的部分代碼:
void route(ThreadData *td)
{
// 加鎖
while (true)
{
pthread_mutex_lock(&td->_mutex); // 加鎖
if (td->_tickets > 0)
{
// 模擬一次搶票的邏輯
usleep(1000);
printf("%s running, get tickets: %d\n", td->_name.c_str(), td->_tickets);
td->_tickets--;
pthread_mutex_unlock(&td->_mutex); // 解鎖
td->_total++;
}
else
{
pthread_mutex_unlock(&td->_mutex); // 解鎖
break;
}
}
}
上面這段代碼模擬了搶票邏輯,將多線(xiàn)程并行搶票通過(guò)鎖的加入變?yōu)榇袌?zhí)行,有效避免了惡意數(shù)據(jù)競(jìng)爭(zhēng)(data race)。
我們不妨假定有兩個(gè)線(xiàn)程同時(shí)執(zhí)行到 加鎖指令 位置:

(上圖左側(cè)部分為加鎖和解鎖對(duì)應(yīng)的匯編語(yǔ)言代碼,其中每一行簡(jiǎn)單匯編指令的執(zhí)行都是原子的)
不妨設(shè)定 thread-1 先進(jìn)入 lock 邏輯 (thread-2先進(jìn)入同理,不影響推斷):
(這里的先進(jìn)入 lock 邏輯,實(shí)際上指的是先執(zhí)行左側(cè)匯編語(yǔ)言中 xchgb &al, mutex 語(yǔ)句)
這就意味著 thread-1先執(zhí)行交換語(yǔ)句,將系統(tǒng)指定初始的 mutex 值 (存儲(chǔ)在內(nèi)存中) 與寄存器初始值 0 進(jìn)行交換,從而寄存器中值變?yōu)?。

由于匯編語(yǔ)言簡(jiǎn)單語(yǔ)句的單行執(zhí)行是原子的,此時(shí)thread-1 已經(jīng)執(zhí)行完 xchgb &al, mutex 語(yǔ)句,所以不排除 thread-2 緊接著也執(zhí)行 xchgb &al, mutex 語(yǔ)句的可能。(線(xiàn)程被切換的時(shí)機(jī)是隨時(shí)的)
這時(shí)我們需要注意:
- CPU寄存器的硬件只有一套,但是寄存器內(nèi)的數(shù)據(jù),屬于線(xiàn)程的硬件上下文 !
- 數(shù)據(jù)在內(nèi)存中存儲(chǔ)時(shí),所有線(xiàn)程都能訪(fǎng)問(wèn),屬于共享資源,但是當(dāng)數(shù)據(jù)從內(nèi)存移動(dòng)到寄存器時(shí),就屬于一個(gè)線(xiàn)程私有了 !
當(dāng)執(zhí)行線(xiàn)程從 thread-1 變?yōu)?thread-2 時(shí),隸屬于 thread-1 的寄存器硬件上下文被取走,thread-1::%al 寄存器值為1,CPU內(nèi)%al寄存器值恢復(fù)為空。
所以,當(dāng) thread-2 執(zhí)行 xchgb &al, mutex 語(yǔ)句時(shí),訪(fǎng)問(wèn)到寄存器內(nèi)存儲(chǔ)的內(nèi)容為自身線(xiàn)程所屬寄存器的初始值(thread-2 先前執(zhí)行了 moveb $0, %al ,所以初始值為0),由于內(nèi)存中 mutex 初始值1已經(jīng)被 thread-1 交換取走,此時(shí)內(nèi)存中 mutex 的值為0,進(jìn)行交換后 %al寄存器 中的值依然為0。
經(jīng)過(guò)匯編的下層判斷語(yǔ)句 if(%al寄存器內(nèi)容 > 0) 不符合條件,故 thread-2 沒(méi)有成功獲得鎖,需要執(zhí)行 goto lock 語(yǔ)句重新申請(qǐng)鎖的資源。

綜上我們可以看到,所有線(xiàn)程在爭(zhēng)鎖的時(shí)候,只有一個(gè) 1 ?。?!
至此,我們發(fā)現(xiàn) thread-2 想要繼續(xù)執(zhí)行,就必須等待 thread-1 釋放鎖,所以程序的執(zhí)行流程就由 thread-1 執(zhí)行到釋放鎖結(jié)束后,將內(nèi)存中 mutex 變量置為1,thread-2 才終止等待,獲得 thread-1 釋放的鎖后,執(zhí)行自身的代碼邏輯。
引入鎖的用途就是為了解決并發(fā)訪(fǎng)問(wèn)出現(xiàn)的問(wèn)題,其問(wèn)題的本質(zhì)是多個(gè)執(zhí)行流同時(shí)執(zhí)行訪(fǎng)問(wèn)全局?jǐn)?shù)據(jù)的代碼造成的。使用鎖保護(hù)全局共享資源的本質(zhì)是通過(guò)保護(hù)臨界區(qū)完成的
以上就是深入探究C/C++中互斥量(鎖)的實(shí)現(xiàn)原理的詳細(xì)內(nèi)容,更多關(guān)于C/C++互斥量(鎖)實(shí)現(xiàn)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C++中priority_queue模擬實(shí)現(xiàn)
本文主要介紹了C++中priority_queue模擬實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2026-04-04
C++順序表實(shí)現(xiàn)圖書(shū)管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++順序表實(shí)現(xiàn)圖書(shū)管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10
如何在C語(yǔ)言中判斷socket是否已經(jīng)斷開(kāi)
如果不主動(dòng)關(guān)閉socket的話(huà),系統(tǒng)不會(huì)自動(dòng)關(guān)閉的,除非當(dāng)前進(jìn)程掛掉了,操作系統(tǒng)把占用的socket回收了才會(huì)關(guān)閉。小編今天跟大家簡(jiǎn)單介紹下如何在C語(yǔ)言中判斷socket是否已經(jīng)斷開(kāi)2019-05-05
C++簡(jiǎn)單實(shí)現(xiàn)消息隊(duì)列的示例代碼
消息隊(duì)列是一種應(yīng)用間的通訊方式,消息發(fā)送后可以立即放回,由消息系統(tǒng)來(lái)確保消息的可靠傳遞,本文主要介紹了C++簡(jiǎn)單實(shí)現(xiàn)消息隊(duì)列的示例代碼,感興趣的可以了解一下2025-11-11
C++中#pragma once與#ifndef對(duì)比分析
當(dāng)我們編寫(xiě)C++代碼時(shí),經(jīng)常需要使用頭文件來(lái)引入一些常用的函數(shù)、類(lèi)或者變量,如果一個(gè)頭文件被重復(fù)包含,就會(huì)導(dǎo)致編譯錯(cuò)誤或者運(yùn)行時(shí)錯(cuò),為了避免發(fā)生,我們需要使用預(yù)處理指令來(lái)防止頭文件被重復(fù)包含,常用的預(yù)處理指令有#pragma once和#ifndef,需要的朋友可以參考下2023-05-05
OpenCV實(shí)現(xiàn)幀差法檢測(cè)運(yùn)動(dòng)目標(biāo)
這篇文章主要為大家詳細(xì)介紹了OpenCV實(shí)現(xiàn)幀差法檢測(cè)運(yùn)動(dòng)目標(biāo),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-03-03
C++?system()函數(shù)的常用用法(全網(wǎng)最新)
system()用于從C?/C++程序調(diào)用操作系統(tǒng)命令,這里給大家講解下C++?system()函數(shù)的常用用法,感興趣的朋友跟隨小編一起看看吧2023-01-01
Qt專(zhuān)欄之模態(tài)與非模態(tài)對(duì)話(huà)框的實(shí)現(xiàn)
這篇文章主要介紹了Qt專(zhuān)欄之模態(tài)與非模態(tài)對(duì)話(huà)框的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04

