C++高頻知識點(十八)

文章目錄

  • 86. C++多線程中,鎖的實現方式有哪些?
    • 1. 互斥鎖(Mutex)
    • 2. 遞歸互斥鎖(Recursive Mutex)
    • 3. 讀寫鎖(Shared Mutex)
    • 4. 自旋鎖(Spinlock)
    • 5. 條件變量(Condition Variable)
  • 87. 內存對齊是什么,為什么要做內存對齊
  • 88. 結構體和聯合體的區別?
  • 89. struct和class的區別?
  • 90. 為什么TCP握手是3次,不能是2次和4次嗎?

86. C++多線程中,鎖的實現方式有哪些?

在這里插入圖片描述

1. 互斥鎖(Mutex)

互斥鎖(std::mutex)是最常見的同步機制,用于保護臨界區,使得同一時刻只有一個線程可以訪問共享資源。

#include <iostream>
#include <thread>
#include <mutex>std::mutex mtx;void print_safe(const std::string& msg) {std::lock_guard<std::mutex> guard(mtx); // 自動加鎖和解鎖std::cout << msg << std::endl;
}int main() {std::thread t1(print_safe, "Hello from thread 1");std::thread t2(print_safe, "Hello from thread 2");t1.join();t2.join();return 0;
}

在這里插入圖片描述

  • std::lock_guard:常用于在作用域范圍內自動管理鎖,確保即使發生異常,鎖也會被正確釋放。

2. 遞歸互斥鎖(Recursive Mutex)

遞歸互斥鎖(std::recursive_mutex)允許同一個線程多次獲得同一把鎖,而不會引起死鎖。適用于遞歸函數或需要多次加鎖的場景。

#include <iostream>
#include <thread>
#include <mutex>std::recursive_mutex rec_mtx;void recursive_function(int n) {if (n <= 0) return;std::lock_guard<std::recursive_mutex> guard(rec_mtx);std::cout << "Recursion depth: " << n << std::endl;recursive_function(n - 1);
}int main() {std::thread t1(recursive_function, 5);t1.join();return 0;
}

在這里插入圖片描述

3. 讀寫鎖(Shared Mutex)

讀寫鎖(std::shared_mutex in C++17)允許多個線程同時讀取數據,但在寫數據時,只有一個線程可以獲得寫鎖。適用于讀操作頻繁、寫操作較少的場景

#include <iostream>
#include <thread>
#include <shared_mutex>
#include <mutex>std::shared_mutex rw_mtx;
int shared_data = 0;void read_data() {std::shared_lock<std::shared_mutex> lock(rw_mtx);std::cout << "Reading data: " << shared_data << std::endl;
}void write_data(int value) {std::unique_lock<std::shared_mutex> lock(rw_mtx);shared_data = value;std::cout << "Writing data: " << shared_data << std::endl;
}int main() {std::thread t1(read_data);std::thread t2(write_data, 42);t1.join();t2.join();return 0;
}

在這里插入圖片描述

4. 自旋鎖(Spinlock)

自旋鎖是一種忙等待的鎖實現,線程在等待鎖的過程中會不斷檢查鎖的狀態,而不是進入休眠。適用于鎖等待時間非常短的場景。

在這里插入圖片描述

#include <atomic>
#include <thread>class Spinlock {std::atomic_flag flag = ATOMIC_FLAG_INIT;public:
/*
atomic_flag.test_and_set(acquire):把標志設為 true,返回設之前的值。
返回 false → 說明之前沒人持鎖 → 你拿到鎖。
返回 true → 已經有人持鎖 → 你就在 while 里原地打轉(自旋)等別人放鎖。
atomic_flag.clear(release):把標志清為 false,表示釋放鎖。
*/void lock() {// 返回true就一直轉圈等// Acquire(獲取):我看見門開了才進去拿資料。// ? 我進門這刻(acquire)之后要讀的東西,不允許被提前到進門之前去讀;進去后能看見別人關門前放好的資料。// test_and_set(acquire):確保拿到鎖后再讀寫共享數據,后續讀寫不會被提前到拿鎖之前。while (flag.test_and_set(std::memory_order_acquire)) {// 自旋等待,什么也不做}}void unlock() {// 放鎖// Release(釋放):我把活兒干完、把資料都裝進箱子,再把“門”關上發出通知。// ? 門關上這刻(release)之前我做的所有修改,都必須先完成,不能被拖到門關之后。// clear(release):確保臨界區里對共享數據的修改,在清鎖之前完成并對外可見。flag.clear(std::memory_order_release);}
};Spinlock spinlock;void critical_section() {spinlock.lock();// 訪問共享資源spinlock.unlock();
}int main() {std::thread t1(critical_section);std::thread t2(critical_section);t1.join();t2.join();return 0;
}
#include <atomic>
#include <thread>
#include <iostream>
#include <chrono>// 把下面這個宏改成 1 可以切到 relaxed 版本做對比
// USE_RELAXED=0(默認):ready.store(..., memory_order_release) + ready.load(..., memory_order_acquire)
// ——正確的發布/獲取配對。// USE_RELAXED=1:把兩邊都改成 memory_order_relaxed
// ——沒有跨線程的可見性保證。
#ifndef USE_RELAXED
#define USE_RELAXED 0
#endifint data = 0;                 // 普通共享數據(非原子)
std::atomic<bool> ready{false}; // 原子標志:告訴對方“數據準備好了”void producer() {data = 42; // 普通寫:把共享數據準備好#if USE_RELAXED// 沒有發布語義:可能發生重排,消費者即便看到 ready=true,也未必能看到 data=42ready.store(true, std::memory_order_relaxed);
#else// 發布(release):保證 data 的寫先于 ready=true 對外可見// 發布:把之前對 data 的寫先“封口發布”ready.store(true, std::memory_order_release);
#endif
}int consumer(int& seen) {
#if USE_RELAXEDwhile (!ready.load(std::memory_order_relaxed)) {// 自旋等待std::this_thread::yield();}
#else// 獲取(acquire):保證看到 ready=true 后,再讀 data 時能看到發布方的修改while (!ready.load(std::memory_order_acquire)) {// std::this_thread::yield(); 是 C++11 提供的線程調度提示(在 <thread> 里)。作用是:把當前線程剩余的時間片“讓出來”,告訴操作系統調度器“我現在沒啥可做了,可以先讓別的就緒線程跑一會兒”。函數返回 void,不拋異常。std::this_thread::yield();          // 讓出時間片,避免滿負荷空轉}
#endifint x = data;   // 普通讀seen = x;return x == 42 ? 0 : 1; // 返回是否出錯
}int main() {// 跑多輪,觀察是否有不一致const int rounds = 100000;  // 可按機器性能調整int failures = 0;for (int i = 0; i < rounds; ++i) {// 每輪復位data = 0;ready.store(false, std::memory_order_relaxed);int seen = -1;std::thread tC([&]{ failures += consumer(seen); });std::thread tP(producer);tP.join();tC.join();// 可選:偶爾打印下現場(避免刷屏)if (i % 25000 == 0) {
#if USE_RELAXEDstd::cout << "[relaxed] round " << i << ", seen=" << seen << "\n";
#elsestd::cout << "[acq/rel] round " << i << ", seen=" << seen << "\n";
#endif}}#if USE_RELAXEDstd::cout << "[relaxed] failures = " << failures<< " / " << rounds << " (未必容易復現,但理論上可能出錯)\n";
#elsestd::cout << "[acquire/release] failures = " << failures<< " / " << rounds << " (應始終為 0)\n";
#endifreturn 0;
}

在這里插入圖片描述

5. 條件變量(Condition Variable)

條件變量(std::condition_variable)并不單獨作為鎖,而是與互斥鎖結合使用。它允許線程在等待某個條件滿足時被阻塞,并在條件滿足時被喚醒。

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>std::mutex mtx;
std::condition_variable cv;
bool ready = false;void worker() {std::unique_lock<std::mutex> lock(mtx);// lock_guard 沒有 unlock()/lock() 接口,生命周期內“始終持有”是它的契約;而 unique_lock 提供了這些成員函數并允許臨時失去所有權// lock_guard 的設計是極簡 RAII:構造即上鎖、析構即解鎖,中間不允許變更持鎖狀態,也不可移動。// unique_lock 的設計是“可擁有/可轉移/可顯式 lock/unlock/release”,契合 wait 在等待期間修改持鎖狀態的需求。// 這是 條件變量的“帶謂詞等待” 用法。// cv.wait(lock, [] { return ready; }); 的意思是:在持有 lock(一個 std::unique_lock<std::mutex>)的前提下,一直等到 ready 為 true 才返回;否則就阻塞等待通知。cv.wait(lock, [] { return ready; }); // 等待條件變量std::cout << "Worker thread is running..." << std::endl;
}void signal() {std::lock_guard<std::mutex> lock(mtx);ready = true;std::cout << "signal thread is running..." << std::endl;cv.notify_one(); // 喚醒等待中的線程
}int main() {std::thread t1(worker);std::thread t2(signal);t1.join();t2.join();return 0;
}

在這里插入圖片描述

87. 內存對齊是什么,為什么要做內存對齊

在這里插入圖片描述
在這里插入圖片描述

88. 結構體和聯合體的區別?

在這里插入圖片描述

#include <iostream>
#include <cstring>  // 用于使用 strcpyunion Data {int i;float f;char str[20];
};int main() {Data data;  // 創建一個聯合體變量// 使用 int 成員data.i = 42;std::cout << "data.i: " << data.i << std::endl;// 使用 float 成員data.f = 3.14;std::cout << "data.f: " << data.f << std::endl;// 使用字符串成員strcpy(data.str, "Hello");std::cout << "data.str: " << data.str << std::endl;// 觀察內存重用的效果,可能會出現未定義的 亂七八糟的內容std::cout << "After setting data.str, data.i: " << data.i << std::endl;std::cout << "After setting data.str, data.f: " << data.f << std::endl;return 0;
}//上面的代碼輸出 可能輸出下面的結果
// data.i: 42 
// data.f: 3.14 
// data.str: Hello After setting data.str, data.i: 1819043144  // 這些值可能是未定義的行為 
// After setting data.str, data.f: 1.15282e+09 // 因為內存已經被str覆蓋

在這里插入圖片描述

89. struct和class的區別?

在這里插入圖片描述

90. 為什么TCP握手是3次,不能是2次和4次嗎?

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

之后我會持續更新,如果喜歡我的文章,請記得一鍵三連哦,點贊關注收藏,你的每一個贊每一份關注每一次收藏都將是我前進路上的無限動力 !!!↖(▔▽▔)↗感謝支持!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/918408.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/918408.shtml
英文地址,請注明出處:http://en.pswp.cn/news/918408.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【C語言強化訓練16天】--從基礎到進階的蛻變之旅:Day1

&#x1f525;個人主頁&#xff1a;草莓熊Lotso &#x1f3ac;作者簡介&#xff1a;C研發方向學習者 &#x1f4d6;個人專欄&#xff1a; 《C語言》 《數據結構與算法》《C語言刷題集》《Leetcode刷題指南》 ??人生格言&#xff1a;生活是默默的堅持&#xff0c;毅力是永久的…

【軟考中級網絡工程師】知識點之 TCP 協議深度剖析

目錄一、TCP 協議簡介二、TCP 協議的特點2.1 面向連接2.2 可靠性高2.3 擁塞控制2.4 全雙工通信2.5 高效性2.6 支持多種應用協議2.7 可靠的錯誤恢復三、TCP 協議的工作機制3.1 三次握手建立連接3.2 數據傳輸3.3 四次揮手關閉連接四、TCP 協議的數據包格式五、TCP 協議在實際應用…

操作系統1.5:操作系統引導

目錄 總覽 什么是操作系統引導&#xff1f; 磁盤里邊有哪些相關數據? 操作系統引導(開機過程&#xff09; 總覽 什么是操作系統引導&#xff1f; 操作系統引導(boot)——開機的時候&#xff0c;怎么讓操作系統運行起來? 磁盤里邊有哪些相關數據? 一個剛買來的磁盤(硬…

[鷓鴣云]光伏AI設計平臺解鎖電站開發新范式

1.[鷓鴣云]平臺概述[鷓鴣云]是由鷓鴣云&#xff08;徐州&#xff09;信息技術有限公司傾力打造的&#xff0c;可以媲美?PVsyst的光伏AI設計平臺。它為光伏項目不同階段的開發提供了快速設計、衛星地圖設計、無人機3D設計、Unity3D設計、專業繪圖設計與場區設計多種設計方式&am…

docker compose和docker-compose命令的區別

Docker Compose 有兩種命令形式&#xff1a;docker compose&#xff08;空格連接&#xff09;docker-compose&#xff08;短橫線連接&#xff09;其核心區別如下&#xff1a;一、技術特性docker-compose&#xff08;短橫線&#xff09;獨立可執行文件&#xff1a;作為獨立程序安…

基于Strands Agent開發輔助閱讀Agent

序 本篇由來&#xff0c;在COC上我當面感謝了組委會和姜寧老師&#xff0c;隨即被姜寧老師催稿&#xff0c;本來當天晚上寫了一個流水賬&#xff0c;感覺甚為不妥。于是決定慢慢寫&#xff0c;緩緩道來。要同時兼顧Show me the code&#xff0c;Show me the vide。希望能形成一…

20250807簡單樹上問題

引入 樹是一種特殊的圖&#xff0c;因其看起來像一顆倒掛的樹而得名。 樹有許多等價的形式化定義&#xff0c;我們這里只取一個&#xff1a;nnn個點n?1n-1n?1條邊的無向連通圖。 樹的直徑 定義樹上任意兩點之間最長的簡單路徑為樹的直徑。 一棵樹可能有很多直徑&#xff0c…

諾基亞就4G/5G相關專利起訴吉利對中國汽車及蜂窩模組企業的影響

諾基亞于2025年7月18日向歐洲統一專利法院&#xff08;UPC&#xff09;曼海姆分庭和德國慕尼黑法院提起訴訟&#xff0c;控訴中國吉利控股集團及其極氪、領克、路特斯、Smart等關聯品牌在未經許可的情況下使用諾基亞4項蜂窩通信標準必要專利 。涉案專利包括1項覆蓋4G/5G的標準必…

Kotlin反射詳解

反射是一種機制&#xff0c;它允許我們在運行時檢查、修改和操作類或對象的內部結構。反射開啟了動態編程的可能性&#xff0c;在開發庫、框架或工具等場景中非常有用。Java 中的反射 在 Java 中&#xff0c;反射一直是實現動態編程的重要基石。它允許開發者在不提前知道類名的…

學習嵌入式-IMX6ULL學習——中斷

volatile&#xff1a;易變的&#xff0c;防止系統優化對寄存器做處理的時候使用&#xff0c;在進行寫1清零操作時&#xff0c;防止該操作被系統優化&#xff1b;一、GIC通用中斷控制器1.GIC通用中斷控制器GIC接收眾多外部中斷&#xff0c;然后對其進行處理&#xff0c;最終通過…

HENGSHI SENSE 6.0 功能-AI 查數助手

面向所有AI Agent開放BI和數據分析能力 AI 查數助手 6.0版本中&#xff0c;我們AI助手的優化是比較深入且全面的。從問答效率到集成能力&#xff0c;都得到了大的躍升&#xff0c;是智能問數應用場景的重大升級以及體驗的全方位優化。我們優化了 AI 助手執行流程&#xff0c;…

降壓型DCDC電源芯片推薦-芯伯樂XBL4001 40V/5A

在電子設備不斷追求高性能與低功耗的今天&#xff0c;電源管理芯片的重要性不言而喻。芯伯樂主推的XBLW-XBL4001芯片&#xff0c;憑借其出色的設計與穩定的性能&#xff0c;為電源管理領域帶來了一款實用的新選擇。一、芯片概述XBLW-XBL4001是一款降壓型&#xff08;Buck&#…

uni-app app端安卓和ios如何申請麥克風權限,喚起提醒彈框

代碼包含功能如下&#xff1a; 1、判斷推送權限是否開啟 2、判斷定位權限是否開啟 3、判斷麥克風權限是否開啟 4、判斷相機權限是否開啟 5、判斷相冊權限是否開啟 6、判斷通訊錄權限是否開啟 7、判斷日歷權限是否開啟 8、判斷備忘錄權限是否開啟 9、Android權限查詢 10、檢查系…

關于 Rust 異步(無棧協程)的相關疑問

這是一個記錄問題求助的文章。關于 waker 與運行時的合作方式我膚淺地學習了 Rust 異步底層實現原理&#xff0c;關于 Future、waker 和運行時等。關于 waker 我有三點猜測&#xff1a;waker 是由實現執行器的人提供的在執行器中會調用 epoll_wait&#xff0c;epoll 返回 fd&am…

stm32項目(25)——基于stm32的植物生長箱環境監測系統

1.實現功能 測 環境溫濕度、光照強度、土壤濕度、水箱水位 手機APP顯示 溫度過低-->打開加熱板 濕度過低-->打開水泵 土壤濕度低-->開水泵 --->只要有指標低于閾值時 就蜂鳴器報警 光強弱-->補光 水位低-->抽水 OLED屏幕實時顯示各種信息 分…

golang 基礎案例_02

1.鎖有時候我們的代碼中可能會存在多個 goroutine 同時操作一個資源&#xff08;臨界區&#xff09;的情況&#xff0c;這種情況下就會發生競態問題&#xff08;數據競態&#xff09;。(1)、互斥鎖&#xff1b;(2)、讀寫互斥鎖&#xff1b;(3)、sync.WaitGroup&#xff1b;(4)、…

C++算法·前綴和

前綴和(Prefix(Prefix(Prefix Sum)Sum)Sum)的定義 前綴和是一種高效處理區間求和問題的算法技巧 其核心思想是通過預處理構建一個前綴和數組 使得后續的區間和查詢可以在常數時間O(1)O(1)O(1)內完成 核心概念 定義 給定一個數組a[1...n]a[1...n]a[1...n],其前綴和數組s[1...…

JavaEE 初階第十七期:文件 IO 的 “管道藝術”(下)

專欄&#xff1a;JavaEE初階起飛計劃 個人主頁&#xff1a;手握風云 目錄 一、Java文件內容寫入 1.1. OutputStream 二、字符流讀取和寫入 2.1. Reader 2.2. Writer 三、示例練習 3.1. 查找文件功能 一、Java文件內容寫入 1.1. OutputStream OutputStream同樣只是?個抽…

【liunx】web高可用---nginx

NGINX簡介Nginx&#xff08;發音為 “engine x”&#xff09;是一款由俄羅斯程序員 Igor Sysoev 開發的 輕量級、高性能的 HTTP 和反向代理服務器&#xff0c;同時也是一個 IMAP/POP3/SMTP 代理服務器。自 2004 年首次發布以來&#xff0c;Nginx 憑借其 高并發處理能力、低內存…

FPGA+護理:跨學科發展的探索(二)

FPGA護理&#xff1a;跨學科發展的探索&#xff08;二&#xff09; 系列文章目錄 FPGA護理&#xff1a;跨學科發展的探索&#xff08;一&#xff09; 文章目錄FPGA護理&#xff1a;跨學科發展的探索&#xff08;二&#xff09;系列文章目錄引言三、FPGA 在精神醫學護理中的應用…