一文講通鎖標記對象std::adopt_lock盲點

一文講通鎖標記對象std::adopt_lock盲點

    • 1. 核心概念
    • 2. 代碼詳解
      • 1. 單個鎖
      • 2. 多重鎖(可以用來預防死鎖)
      • 3. 條件變量的互斥控制
      • 4. 復雜示例: 多生產者-多消費者模型(超綱了, 可不看,哈哈哈哈)
    • 3. 小結

1. 核心概念

??在C++中, std::adopt_lock是一個鎖標記對象[^1], 用于配合鎖對象(如 std::lock_guard、std::unique_lock 或 std::shared_lock)來管理互斥鎖(mutex), 它的作用是告訴鎖對象:互斥鎖已經被手動鎖定了,鎖對象只需要“接管”這個鎖的所有權,而不需要再次嘗試鎖定。

2. 代碼詳解

1. 單個鎖

#include <iostream>
#include <mutex>
#include <thread>std::mutex mtx;  // Global mutexvoid process() {// Step 1: Manually lock the mutex.mtx.lock();  // The current thread now owns the mutex.// Step 2: Construct a lock_guard to adopt the existing lock.// The std::adopt_lock tag tells lock_guard that mtx is already locked.std::lock_guard<std::mutex> guard(mtx, std::adopt_lock);// Critical section: safe access to shared resources.std::cout << "Inside critical section." << std::endl;// When 'guard' goes out of scope, its destructor will call mtx.unlock().
}int main() {std::thread t(process);t.join();  // Wait for the thread to finish.return 0;
}

??這里的關鍵點是 std::adopt_lock,它告訴 lock_guard 互斥量已經被鎖定,因此 lock_guard 不會嘗試再次調用
mtx.lock()

如果沒有使用 std::adopt_lock,std::lock_guard 會在構造時試圖鎖定互斥量,這將導致死鎖

2. 多重鎖(可以用來預防死鎖)

#include <iostream>
#include <mutex>
#include <thread>std::mutex mtx1;
std::mutex mtx2;void task() {// Step 1: Atomically lock both mutexes using std::lock, which prevents deadlock.std::lock(mtx1, mtx2);// Step 2: Create RAII objects that adopt these locks.std::lock_guard<std::mutex> guard1(mtx1, std::adopt_lock);std::lock_guard<std::mutex> guard2(mtx2, std::adopt_lock);// Critical section: safe access to shared resources protected by mtx1 and mtx2.std::cout << "Thread safely acquired both mutexes." << std::endl;// Both mutexes will be unlocked when guard1 and guard2 go out of scope.
}int main() {std::thread t1(task);std::thread t2(task);t1.join();t2.join();return 0;
}

3. 條件變量的互斥控制

??在條件變量中結合 std::unique_lock 和 std::adopt_lock 使用,可以靈活地管理鎖的狀態。

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>std::mutex mtx;
std::condition_variable cv;
bool ready = false;void workerThread() {// 手動鎖定互斥量mtx.lock();std::cout << "Worker thread acquired lock manually.\n";// 使用 adopt_lock 轉移鎖管理權std::unique_lock<std::mutex> lock(mtx, std::adopt_lock);// 等待條件變量被通知cv.wait(lock, [] { return ready; });std::cout << "Worker thread is processing data.\n";
}void notifierThread() {std::this_thread::sleep_for(std::chrono::seconds(1));// 通知條件變量{std::lock_guard<std::mutex> lock(mtx); // 自動管理鎖ready = true;std::cout << "Notifier thread is notifying.\n";}cv.notify_one();
}int main() {std::thread worker(workerThread);std::thread notifier(notifierThread);worker.join();notifier.join();return 0;
}

解釋補充

  • worker_thread 手動鎖定互斥量并通過 std::adopt_lock 轉移鎖管理權給 std::unique_lock。
  • notifier_thread 通過 std::lock_guard 安全通知條件變量。

4. 復雜示例: 多生產者-多消費者模型(超綱了, 可不看,哈哈哈哈)

??假設有多個生產者線程向共享隊列中添加任務,而多個消費者線程從隊列中處理任務。為了避免死鎖,使用 std::adopt_lock 配合多個互斥量和條件變量。

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <vector>
#include <chrono>std::mutex queue_mutex;         // 隊列的互斥量
std::mutex print_mutex;         // 打印輸出的互斥量
std::condition_variable cv;     // 條件變量
std::queue<int> task_queue;     // 共享任務隊列
const int MAX_QUEUE_SIZE = 10;  // 隊列的最大容量
bool stop = false;              // 用于通知消費者線程停止// 生產者函數
void producer(int id) {for (int i = 0; i < 20; ++i) {std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模擬生產延遲std::unique_lock<std::mutex> lock(queue_mutex); // 鎖定隊列的互斥量cv.wait(lock, [] { return task_queue.size() < MAX_QUEUE_SIZE; }); // 等待隊列有空間task_queue.push(i);{// 使用 adopt_lock 安全打印日志std::lock_guard<std::mutex> print_lock(print_mutex, std::adopt_lock);std::cout << "Producer " << id << " produced task " << i << ". Queue size: " << task_queue.size() << std::endl;}cv.notify_all(); // 通知消費者}
}// 消費者函數
void consumer(int id) {while (true) {std::unique_lock<std::mutex> lock(queue_mutex);cv.wait(lock, [] { return !task_queue.empty() || stop; }); // 等待隊列有任務或停止信號if (stop && task_queue.empty()) break; // 如果停止并且隊列為空,退出int task = task_queue.front();task_queue.pop();{// 使用 adopt_lock 安全打印日志std::lock_guard<std::mutex> print_lock(print_mutex, std::adopt_lock);std::cout << "Consumer " << id << " consumed task " << task << ". Queue size: " << task_queue.size() << std::endl;}cv.notify_all(); // 通知生產者}
}int main() {std::vector<std::thread> producers;std::vector<std::thread> consumers;// 啟動生產者線程for (int i = 0; i < 3; ++i) {producers.emplace_back(producer, i + 1);}// 啟動消費者線程for (int i = 0; i < 2; ++i) {consumers.emplace_back(consumer, i + 1);}// 等待所有生產者完成for (auto& p : producers) {p.join();}// 通知消費者停止{std::lock_guard<std::mutex> lock(queue_mutex);stop = true;}cv.notify_all();// 等待所有消費者完成for (auto& c : consumers) {c.join();}std::cout << "All tasks processed. Exiting program." << std::endl;return 0;
}

3. 小結

std::adopt_lock 適用于以下場景:

  • Lock First, Adopt Later:手動鎖定互斥量后,將管理權交給鎖管理類(如 std::lock_guard 或 std::unique_lock)。
  • 注釋要清晰(就是這么突兀! 沒錯, 就是沒有這個場景!!!, 想想我為什么要寫?還標紅加粗)
  • 多個互斥量的協調鎖定。
  • 配合條件變量靈活管理鎖定邏輯。

[^1] 鎖標記對象

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

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

相關文章

LVI-SAM、VINS-Mono、LIO-SAM算法的閱讀參考和m2dgr數據集上的復現(留作學習使用)

ROS一鍵安裝參考&#xff1a; ROS的最簡單安裝——魚香一鍵安裝_魚香ros一鍵安裝-CSDN博客 opencv官網下載4.2.0參考&#xff1a;https://opencv.org/releases/page/3/ nvidia驅動安裝:ubuntu18.04 安裝顯卡驅動 - 開始戰斗 - 博客園 cuda搭配使用12 cuda安裝1&#xff1a;Ub…

基于jspm校園安全管理系統(源碼+lw+部署文檔+講解),源碼可白嫖!

摘要 隨著信息時代的來臨&#xff0c;過去信息校園安全管理方式的缺點逐漸暴露&#xff0c;本次對過去的校園安全管理方式的缺點進行分析&#xff0c;采取計算機方式構建校園安全管理系統。本文通過閱讀相關文獻&#xff0c;研究國內外相關技術&#xff0c;提出了一種集安全教…

基于NXP+FPGA軌道交通3U機箱結構牽引控制單元

基于NXPFPGA軌道交通異步電機牽引控制單元(TCU-IM) 異步電機牽引控制單元&#xff08;TCU-IM&#xff09;用于牽引逆變器-異步電機構成的牽引電傳動系統&#xff0c;可采用車控或架控方式。執行高性能異步電機復矢量控制策略&#xff0c;具有響應迅速、有效可靠的防空轉滑行控制…

《CircleCI:CircleCI:解鎖軟件開發持續集成(CI)和持續部署(CD)高效密碼》:此文為AI自動生成

《CircleCI&#xff1a;CircleCI&#xff1a;解鎖軟件開發持續集成&#xff08;CI&#xff09;和持續部署&#xff08;CD&#xff09;高效密碼》&#xff1a;此文為AI自動生成 一、CircleCI 初印象 在當今軟件開發的快節奏賽道上&#xff0c;持續集成&#xff08;CI&#xff…

基于MySQL有用戶管理的音樂播放器

基于MySQL的音樂器 帶有用戶登錄功能驗證用戶身份&#xff0c;用戶注冊等操作還有用戶音樂列表&#xff0c;以及增刪查改操作 INSERT into users(username,passwd,phone_number,created_time,role) VALUES(‘張三’,‘123456’,‘123’,‘2025-3-11’,‘1’) 三張表&#xf…

差分專題練習 ——基于羅勇軍老師的《藍橋杯算法入門C/C++》

一、1.重新排序 - 藍橋云課 算法代碼&#xff1a; #include <bits/stdc.h> using namespace std; const int N 1e5 3;int a[N], d[N], cnt[N];int main() {int n; scanf("%d", &n);for (int i 1; i < n; i) scanf("%d", &a[i]);int m…

AI+視頻監控電力巡檢:EasyCVR視頻中臺方案如何賦能電力行業智能化轉型

隨著電力行業的快速發展&#xff0c;電力設施的安全性、穩定性和運維效率變得至關重要。傳統視頻監控系統在實時性、智能化及多系統協同等方面面臨嚴峻挑戰。EasyCVR視頻中臺解決方案作為一種先進的技術手段&#xff0c;在電力行業中得到了廣泛應用&#xff0c;為電力設施的監控…

【哈希表與字符串的算法之路:思路與實現】—— LeetCode

文章目錄 兩數之和面試題01.02.判定是否為字符重排存在重復元素存在重復元素||字母異位詞分組最長公共前綴和最長回文子串二進制求和字符串相乘 兩數之和 這題的思路很簡單&#xff0c;在讀完題目之后&#xff0c;便可以想到暴力枚舉&#xff0c;直接遍歷整個數組兩遍即可&…

RabbitMQ入門:從安裝到高級消息模式

文章目錄 一. RabbitMQ概述1.1 同步/異步1.1.1 同步調用1.1.2 異步調用 1.2 消息中間件1.2.1 概念1.2.2 作用1.2.3 常見的消息中間件1.2.4 其他中間件 1.3 RabbitMQ1.3.1 簡介1.3.2 特點1.3.3 方式1.3.4 架構1.3.5 運行流程 二. 安裝2.1 Docker 安裝 RabbitMQ 三. 簡單隊列&…

kernel與modules解耦

一、耦合&#xff1a; linux的kernel與modules存在耦合版本匹配&#xff0c;在版本不匹配&#xff08;內核重新編譯后&#xff0c;或者驅動模塊編譯依賴的內核版本跟運行版本不匹配&#xff09;時候&#xff0c;會存在insmod 驅動模塊失敗的情形&#xff1b; 二、解耦&#xff…

物理約束神經網絡(PINN)和有限元方法哪個更接近“真正的物理規律”?還是兩者只是不同的數學表達?

物理約束神經網絡(Physics-Informed Neural Networks, PINN)和有限元方法(Finite Element Method, FEM)是兩種在科學計算和工程模擬中廣泛應用的數值方法。PINN 依賴深度學習來近似微分方程的解,并在訓練過程中將物理約束作為損失項融入網絡,而 FEM 通過將連續介質的物理…

UI程序的std::cout重定向輸出到Visual Studio的debug輸出窗口

常用代碼。 UI程序的std::cout重定向輸出到Visual Studio的debug輸出窗口 #include <iostream> #include <streambuf> #include <vector> #include <string> #include <afxwin.h> //MFC// 自定義 streambuf 類&#xff0c;用于重定向輸出到 Vis…

Python開發合并多個PDF文件

前言 在我們的工作中&#xff0c;可能有以下場景需要用到合并多個PDF&#xff1a; 文檔歸檔&#xff1a;在企業或組織中&#xff0c;常常需要將相關的文檔&#xff08;如合同、報告、發票等&#xff09;合并為一個PDF文件&#xff0c;以便于歸檔和管理。 報告生成&#xff1a;在…

DeepSeek 助力 C++ 開發:探索智能編程新境界

這篇文章就會詳細講講 DeepSeek 在 C 開發里到底能怎么用&#xff0c;從上面說的寫代碼、找錯誤、優化性能&#xff0c;到管理項目這些方面&#xff0c;還會給出好多實際的代碼例子&#xff0c;講講實際用起來是啥情況。目的就是給那些做 C 開發的人&#xff0c;一份全面又詳細…

C#-使用VisualStudio編譯C#工程

一.創建csproj文件 二.創建源cs文件 三.生成解決方案 四.運行解決方案 五.VisualStudio功能列表 <1.代碼格式化: CtrlKD完成代碼整體格式化 <2.窗口布局 窗口->重置窗口布局 <3.引用查找&關聯 <4.包管理 <5.日志輸出級別 工具->選項->項目解決方案…

Kafka相關的面試題

以下是150道Kafka相關的面試題及簡潔回答&#xff1a; Kafka基礎概念 1. 什么是Kafka&#xff1f; Kafka是一個分布式、可擴展、容錯的發布-訂閱消息系統&#xff0c;最初由LinkedIn開發&#xff0c;現為Apache項目。它適用于高吞吐量的場景&#xff0c;如大數據處理和實時數據…

CTF--Web安全--SQL注入之報錯注入

CTF–Web安全–SQL注入之報錯注入 一、報錯注入的概念 用戶使用數據庫查詢語句&#xff0c;向數據庫發送錯誤指令&#xff0c;數據庫返回報錯信息&#xff0c;報錯信息中參雜著我們想要獲取的隱私數據。通常在我們在頁面顯示中找不到回顯位的時候&#xff0c;使用報錯注入。 二…

深度學習中學習率調整策略

學習率衰減策略是深度學習優化過程中的一個關鍵因素&#xff0c;它決定了訓練過程中學習率的調整方式&#xff0c;從而影響模型收斂的速度和效果。不同的衰減策略在不同的任務和模型上可能有不同的表現&#xff0c;下面從我用到過的幾個衰減策略進行記錄&#xff0c;后續慢慢跟…

JavaCV

調用攝像頭 public class Camera {public static void main(String[] args) throws FrameGrabber.Exception {// 開啟抓取器OpenCVFrameGrabber grabber new OpenCVFrameGrabber(0);grabber.start();// 開啟窗口CanvasFrame canvasFrame new CanvasFrame("OpenCV Frame…

凝思linux修改mac地址

臨時性修改 /sbin/ifconfig eth0 hw ether 00:0C:29:36:97:20