`lock()` 和 `unlock()` 線程同步函數

1) 函數的概念與用途

lock()unlock() 不是特定的標準庫函數,而是線程同步原語的一般概念,用于在多線程環境中保護共享資源。在不同的編程環境和庫中,這些函數有不同的具體實現(如 POSIX 線程的 pthread_mutex_lock() 或 C++ 的 std::mutex::lock())。

可以將 lock()unlock() 想象成"資源門的鑰匙":當一個線程需要訪問共享資源時,它必須先獲取鎖(拿到鑰匙),使用完資源后釋放鎖(歸還鑰匙)。這樣可以確保同一時間只有一個線程能訪問受保護的資源,防止數據競爭和不一致。

典型應用場景包括:

  • 共享數據保護:保護多線程共享的變量、數據結構
  • 臨界區控制:確保代碼關鍵部分只能由一個線程執行
  • 資源訪問序列化:對有限資源(如文件、網絡連接)的有序訪問
  • 生產者-消費者模式:協調生產者和消費者線程之間的數據交換

2) 函數的聲明與出處

鎖的實現因平臺和編程語言而異,以下是幾種常見實現:

POSIX 線程 (pthread)

#include <pthread.h>int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);

C++ 標準庫

#include <mutex>std::mutex mtx;
mtx.lock();    // 獲取鎖
mtx.unlock();  // 釋放鎖

Windows API

#include <windows.h>CRITICAL_SECTION cs;
EnterCriticalSection(&cs);   // 獲取鎖
LeaveCriticalSection(&cs);   // 釋放鎖

3) 參數詳解:互斥鎖對象

對于 POSIX 線程的 pthread_mutex_lock/unlock

  • pthread_mutex_t *mutex
    • 作用:指向要鎖定/解鎖的互斥鎖對象的指針
    • 要求:互斥鎖必須已通過 pthread_mutex_init() 初始化
    • 注意:不同類型的互斥鎖有不同的特性(普通、遞歸、錯誤檢查等)

4) 返回值:操作狀態

對于 POSIX 線程的 pthread_mutex_lock/unlock

  • 返回值類型int
  • 返回值含義
    • 成功:返回 0
    • 失敗:返回錯誤碼(如 EINVAL 無效參數,EDEADLK 死鎖等)

5) 實戰演示:多種使用場景

示例 1:POSIX 線程保護共享變量

#include <stdio.h>
#include <pthread.h>pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int shared_counter = 0;void* thread_function(void* arg) {for (int i = 0; i < 100000; i++) {// 獲取鎖pthread_mutex_lock(&mutex);// 臨界區開始shared_counter++;// 臨界區結束// 釋放鎖pthread_mutex_unlock(&mutex);}return NULL;
}int main() {pthread_t thread1, thread2;pthread_create(&thread1, NULL, thread_function, NULL);pthread_create(&thread2, NULL, thread_function, NULL);pthread_join(thread1, NULL);pthread_join(thread2, NULL);printf("Final counter value: %d (expected: 200000)\n", shared_counter);pthread_mutex_destroy(&mutex);return 0;
}

示例 2:C++ 使用 std::mutex

#include <iostream>
#include <thread>
#include <mutex>
#include <vector>std::mutex mtx;
int shared_value = 0;void increment() {for (int i = 0; i < 100000; i++) {mtx.lock();        // 獲取鎖shared_value++;    // 臨界區mtx.unlock();      // 釋放鎖}
}int main() {std::vector<std::thread> threads;for (int i = 0; i < 10; i++) {threads.emplace_back(increment);}for (auto& t : threads) {t.join();}std::cout << "Final value: " << shared_value << " (expected: 1000000)" << std::endl;return 0;
}

示例 3:使用 RAII 避免忘記解鎖 (C++)

#include <iostream>
#include <thread>
#include <mutex>
#include <vector>std::mutex mtx;
int shared_value = 0;void increment() {for (int i = 0; i < 100000; i++) {// 使用 std::lock_guard 自動管理鎖生命周期std::lock_guard<std::mutex> lock(mtx);shared_value++; // 臨界區// lock 析構時自動釋放鎖}
}int main() {std::vector<std::thread> threads;for (int i = 0; i < 10; i++) {threads.emplace_back(increment);}for (auto& t : threads) {t.join();}std::cout << "Final value: " << shared_value << " (expected: 1000000)" << std::endl;return 0;
}

6) 編譯方式與注意事項

編譯 POSIX 線程程序:

gcc -o lock_demo lock_demo.c -lpthread

編譯 C++ 程序:

g++ -o lock_demo lock_demo.cpp -std=c++11 -lpthread

關鍵注意事項:

  1. 死鎖風險:不正確使用鎖可能導致死鎖(多個線程互相等待對方釋放鎖)
  2. 性能影響:過度使用鎖會降低程序性能,應盡量減少鎖的持有時間
  3. 鎖粒度:選擇適當的鎖粒度(粗粒度減少開銷但降低并發性,細粒度提高并發性但增加開銷)
  4. 異常安全:在 C++ 中使用 RAII 模式(如 std::lock_guard)確保異常時鎖能被正確釋放
  5. 鎖類型選擇:根據需求選擇合適的鎖類型(普通鎖、遞歸鎖、讀寫鎖等)

7) 執行結果說明

示例 1 輸出:

Final counter value: 200000 (expected: 200000)

展示了如何使用互斥鎖保護共享計數器,確保兩個線程各增加 100,000 次后結果為 200,000。

示例 2 輸出:

Final value: 1000000 (expected: 1000000)

顯示了 C++ 中使用 std::mutex 保護共享變量,10 個線程各增加 100,000 次后結果為 1,000,000。

示例 3 輸出:

Final value: 1000000 (expected: 1000000)

演示了使用 RAII 模式(std::lock_guard)自動管理鎖的生命周期,避免忘記解鎖。

8) 總結:鎖的工作流程與價值

鎖的工作流程可以總結如下:

線程嘗試獲取鎖 lock()
鎖是否可用?
獲取鎖, 進入臨界區
線程阻塞等待
執行臨界區代碼
訪問共享資源
釋放鎖 unlock()
其他線程可以競爭鎖

鎖是多線程編程中的核心同步機制,它的價值在于:

  1. 數據一致性:防止多個線程同時修改共享數據導致的不一致
  2. 執行有序性:確保臨界區代碼的原子性執行
  3. 線程協調:協調多個線程對有限資源的訪問
多線程同步需求
如何選擇同步機制?
保護共享數據
使用互斥鎖 Mutex
讀寫分離場景
使用讀寫鎖 R/W Lock
線程間通知
使用條件變量 Condition Variable
一次性初始化
使用 once_flag

最佳實踐建議:

  1. 最小化臨界區:盡量減少鎖的持有時間,只保護真正需要同步的代碼
  2. 避免嵌套鎖:盡量避免在持有鎖時獲取其他鎖,防止死鎖
  3. 使用RAII模式:在C++中使用std::lock_guardstd::unique_lock自動管理鎖
  4. 鎖順序一致:如果必須使用多個鎖,確保所有線程以相同順序獲取它們
  5. 考慮替代方案:根據場景考慮使用無鎖編程、原子操作或其他同步機制

lock()unlock() 是多線程編程的基礎工具,正確使用它們對于編寫線程安全、高效并發的程序至關重要。掌握鎖的原理、使用方法和注意事項,可以幫助開發者避免常見的多線程問題,如數據競爭、死鎖和性能瓶頸。

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

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

相關文章

升級openssh后ORACLE RAC EM 安裝失敗處理

升級過程中由于SCP傳輸時目標目錄/tmp/tempRACTrans_2025_08_22--18-25-44-032/ractrans 不存在導致的OC4J配置失敗&#xff1a;WARNING: /usr/bin/scp: dest open "/tmp/tempRACTrans_2025_08_22--18-25-44-032/ractrans": No such file or directory/usr/bin/scp…

ADB 調試工具的學習[特殊字符]

一、ADB 的工作原理 1.1 ADB 概念 ADB (Android Debug Bridge)&#xff1a;Android 調試橋&#xff0c;是開發/測試 Android 應用必備的調試工具。作用&#xff1a;通過 電腦終端命令 操作 安卓手機/模擬器。 1.2 ADB 構成與原理 ADB 由三部分組成&#xff1a; Client 端&#…

用一根“數據中樞神經”串起業務從事件流到 Apache Kafka

1. 為什么是“事件流”&#xff1f; 在一個軟件定義、自動化、永遠在線的世界里&#xff0c;系統之間最需要的是&#xff1a;把發生了什么這件事&#xff0c;第一時間、按正確順序、可靠地傳到該知道的人/系統那里。 事件流就像企業的中樞神經&#xff1a;它把數據庫更新、設備…

【RAGFlow代碼詳解-4】數據存儲層

數據庫基礎設施 RAGFlow 使用關系數據庫&#xff08;MySQL 或 PostgreSQL&#xff09;作為主要元數據存儲&#xff0c;通過具有連接池和重試機制的 Peewee ORM 進行管理。 連接管理 數據庫連接通過 service_conf.yaml 和環境變量進行配置。該系統支持具有可配置連接池的 MySQL …

ES_映射

一、 映射&#xff08;Mapping&#xff09;是什么&#xff1f; 簡單來說&#xff0c;映射就像是關系型數據庫中的表結構定義&#xff08;Schema&#xff09;。它定義了索引&#xff08;Index&#xff09;中的文檔&#xff08;Document&#xff09;可以包含哪些字段&#xff08;…

【Linux | 網絡】多路轉接IO之poll

一、poll函數二、poll的優缺點三、實現poll服務器&#xff08;只關心讀事件&#xff09;3.1 Log.hpp&#xff08;日志&#xff09;3.2 Lockguard.hpp&#xff08;自動管理鎖&#xff09;3.3 Socket.hpp&#xff08;封裝套接字&#xff09;3.4 PollServer.hpp&#xff08;服務端…

一站式資源共享平臺模板,助力快速搭建專屬資源站源碼

內容目錄一、詳細介紹二、效果展示1.部分代碼2.效果圖展示三、學習資料下載一、詳細介紹 這個資源分享網站模板是一個功能完整、設計現代的單頁網站&#xff0c;非常適合快速搭建資源分享平臺。以下是關于這個模板的詳細介紹&#xff0c;幫助你更好地理解并發布到自己的網站&a…

ngnix的部分配置

1. 禁止特定IP地址訪問你可以通過在Nginx配置文件中添加deny指令來阻止特定IP地址或IP地址段的訪問。server {listen 80;server_name example.com;location / {deny 192.168.1.0/24;allow all;} }2. 允許特定IP地址訪問如果你想允許只有特定IP地址或IP地址段的訪問&#xff0c;…

Qwt7.0-打造更美觀高效的Qt開源繪圖控件庫

概述 Qt 生態里能畫圖的庫不多&#xff0c;主流的為QCustomPlot、Qwt、Qt Charts和KDChart&#xff0c;Qt6.8之后把原來的 Qt Charts&#xff08;2D&#xff09; 與 Qt DataVisualization&#xff08;3D&#xff09; 合并為統一的Qt Graphs模塊&#xff08;注意不是Qt Graphic…

NFC線圈設計計算

對工作于13.56MHz的電感耦合的NFC系統,針對小距離的傳統天線通常是環形或者矩形的扁平線圈。 圓形扁平線圈計算評估 對于二階估計,我們可以由匝數決定的電感等式為 考慮到線圈的物理參數,設置平均直徑:D_averD0-N(gw) 線圈周長: &#xff1b;d2*(w t)/π 初始設置中的這種電感…

mac設置鼠標滾輪方向

mac中滾輪的滑動方向和windows是相反的&#xff0c;如果需要設置和windows相同&#xff0c;設置如下&#xff1a;將自然滾動關閉即可。

QSpinBox的用法及其使用QSS對其美化

摘要 在現代應用程序開發中&#xff0c;提供一個直觀且用戶友好的界面至關重要。Qt框架提供了豐富的控件和工具&#xff0c;幫助開發者實現這一目標。本文將詳細介紹如何使用Qt的QSpinBox控件讓用戶輸入數值&#xff0c;并通過Qt Style Sheets (QSS) 美化界面&#xff0c;提升…

18 繼續學習

要設計出一個好的系統&#xff0c;需要多年的知識積累。有一個捷徑是研究真實世界的系統架構。本文將介紹一些有幫助的閱讀材料。 務必留意那些真實系統之間共通的原理和相同的底層技術。研究每個技術并了解它解決了什么問題&#xff0c; 這是一個鞏固基礎知識和完善設計過程的…

深度學習篇---混淆矩陣

要理解混淆矩陣&#xff08;Confusion Matrix&#xff09;&#xff0c;我們可以從它的名字入手&#xff1a;它本質是一張 “幫你理清模型預測結果到底‘混淆’在哪里” 的表格&#xff0c;核心作用是評估分類模型的表現 —— 比如判斷一張圖片是 “貓” 還是 “狗”、一封郵件是…

MySQL重大隱患!mysqlpump的--set-gtid-purged參數在5.7和8.0的雷區

MySQLPump是MySQL官方提供的一個用于備份和恢復MySQL數據庫的工具。它于MySQL 5.7.8版本中首次引入&#xff0c;旨在提供一種快速、可靠且高效的備份和恢復解決方案。MySQL Pump首次支持了并行導出、壓縮導出&#xff0c;可以利用多核CPU來提高備份能力&#xff0c;在效率上要比…

低質量視頻變高清AI:告別模糊,重現清晰畫質

在數字時代&#xff0c;視頻內容的創作和消費日益普及&#xff0c;然而&#xff0c;許多早期拍攝或存儲的視頻&#xff0c;由于技術限制或壓縮等原因&#xff0c;往往存在畫質不佳的問題&#xff0c;如模糊、噪點多、分辨率低等。這不僅影響觀看體驗&#xff0c;也限制了這些珍…

Linux入門教程 第十二章 防火墻

文章目錄前言一、 iptables 概述Netfilter二、iptables 的表、鏈結構2.1 ptables的四表五鏈結構介紹2.1.1 四表五鏈2.1.2 四表2.1.3 **五鏈**2.2 數據包過濾的匹配流程&#xff08;數據包到防火墻&#xff09;2.2.1 規則鏈之間的匹配順序:主機型防火墻:2.2.2 規則鏈內的匹配順序…

單詞搜索+回溯法

題目&#xff1a;思考&#xff1a; 1.經典回溯 實現&#xff1a; class Solution { public:bool find_word(vector<vector<char>>&board,string word,int pos,int i,int j){bool retfalse;if (posword.size()-1) return board[i][j]word[pos];if (board[i][j…

【嵌入式開發 Linux 常用命令系列 8 -- git checkout 解沖突詳細介紹】

文章目錄1. Git 沖突產生的場景2. 沖突標記符號解釋3. git checkout --ours 和 git checkout --theirs語法含義使用場景4. 操作完成后的流程5. 舉例演示1. Git 沖突產生的場景 當你在 git merge、git rebase、git cherry-pick 等操作時&#xff0c;如果 同一個文件的同一部分在…

16-day13強化學習和訓練大模型

強化學習 強化學習和監督學習是機器學習中的兩種不同的學習范式 強化學習&#xff1a;目標是讓智能體通過與環境的交互&#xff0c;學習到一個最優策略&#xff0c;以最大化長期累積獎勵。 例如&#xff0c;在機器人導航任務中&#xff0c;智能體需要學習如何在復雜環境中移動&…