[特殊字符]?[特殊字符]Linux驅動開發入門 | 并發與互斥機制詳解

文章目錄

  • 👨?💻Linux驅動開發入門 | 并發與互斥機制詳解
    • 📌為什么驅動中需要并發和互斥控制?
    • 💡常見的并發控制機制
    • 🔐自旋鎖和信號量通俗理解
      • 🌀自旋鎖(Spinlock)——“廁所排隊鎖”
      • 🚦信號量(Semaphore)——“停車場智能顯示器”
    • 🆚 自旋鎖 vs 信號量
    • 讀寫鎖是什么?
    • 🚨死鎖問題和解決策略
      • 一、預防死鎖
        • 1. 資源一次性分配(破壞請求與保持條件)
        • 2. 可剝奪資源(破壞不可剝奪條件)
        • 3. 資源有序分配法(破壞循環等待條件)
      • 二、避免死鎖
        • 銀行家算法
      • 三、死鎖檢測
        • 步驟如下:
      • 四、解除死鎖
        • 1. 剝奪資源
        • 2. 撤消進程
      • 五、避免死鎖的編程實踐
        • 1. 加鎖順序(Lock Ordering)
        • 2. 加鎖時限(Try Lock with Timeout)
        • 3. 死鎖檢測機制
      • 總結
    • 🧪真實驅動例子:互斥訪問設備寄存器
      • 臨界區:
    • 🧠Q&A 常見問題
    • ?總結

👨?💻Linux驅動開發入門 | 并發與互斥機制詳解

📌為什么驅動中需要并發和互斥控制?

我們知道,在多線程或多任務并行執行的操作系統中,比如Linux內核,多個執行單元(線程或中斷)可能同時訪問共享資源(如全局變量、設備寄存器、緩沖區等),這就帶來了“競態條件(Race Condition)”的風險。

舉個簡單的例子:
假如兩個線程A和B幾乎在同一時間讀取同一個計數變量x的值為10,然后各自+1并寫回。你期望x變為12,但結果可能還是11。

這類問題就需要“互斥”機制來保護——確保同一時刻只能有一個執行單元訪問共享資源,其訪問的代碼區域稱為臨界區(Critical Section)


💡常見的并發控制機制

Linux驅動開發中,常見的互斥控制方式有以下幾種:

互斥機制特點場景
中斷屏蔽禁止中斷上下文干擾適用于簡單、快速完成的臨界區
原子操作使用CPU原子指令保證變量操作完整操作變量極少時
自旋鎖(spinlock)自旋等待,適合短時間鎖定中斷/進程上下文
信號量(semaphore)可睡眠等待,適合長時間持鎖進程上下文,驅動任務中常用
互斥鎖(mutex)是信號量的簡化版本一般用于用戶態/驅動模塊

🔐自旋鎖和信號量通俗理解

🌀自旋鎖(Spinlock)——“廁所排隊鎖”

把共享資源想象成一個單人廁所。

  • 線程A進入廁所,并鎖門(獲取鎖);
  • 線程B也想用廁所,只能在門口一直轉圈圈(不停檢查鎖狀態);
  • A出來后釋放鎖,B才能進去。

自旋鎖適合鎖定時間非常短的臨界區,因為等待期間線程一直占用CPU,不睡覺!

? 優點:

  • 實時性好(適合中斷上下文)
  • 實現簡單

? 缺點:

  • CPU占用率高,鎖持有久了會浪費資源
  • 不可在臨界區使用可能睡眠的代碼!

🚦信號量(Semaphore)——“停車場智能顯示器”

假設一個停車場有100個車位,信號量就相當于入口處的電子屏:

  • 顯示“當前車位:20”,車還能進;
  • 顯示“滿”,車就得等;
  • 有車離開,車位更新,通知其他等車入場。

信號量適合臨界區操作時間較長、可能會阻塞的場景

? 優點:

  • 可睡眠等待,不占CPU
  • 適合處理資源池問題,如連接池、緩存池等

? 缺點:

  • 實時性差,不可用于中斷處理
  • 實現復雜,需考慮死鎖
  • 鎖被短時間持有時,使用信號量就不太適宜了,因為睡眠引起的耗時可能比鎖被占用的全部時間還要長。

🆚 自旋鎖 vs 信號量

對比項自旋鎖信號量
是否睡眠? 不可睡眠? 可睡眠等待
適用上下文中斷上下文進程上下文
臨界區時長極短可長
是否允許搶占? 不允許(禁搶)? 允許搶占
用于中斷中? 可以? 禁止
是否可重入? 否? 是(看實現)

在你占用信號量的同時不能占用自旋鎖,因為在你等待信號量時可能會睡眠,而在持有自旋鎖時是不允許睡眠的。


讀寫鎖是什么?

當臨界區的一個文件可以被同時讀取,但是并不能被同時讀和寫。如果一個線程在讀,另一個線程在寫,那么很可能會讀取到錯誤的不完整的數據。讀寫自旋鎖是可以允許對臨界區的共享資源進行并發讀操作的。但是并不允許多個線程并發讀寫操作

🚨死鎖問題和解決策略

在操作系統或并發編程中,**死鎖(Deadlock)**是一個經典問題。本文將帶你由淺入深地了解死鎖的處理方式,主要包括四種:預防死鎖、避免死鎖、檢測死鎖以及解除死鎖。


一、預防死鎖

死鎖產生的四個必要條件是:互斥、不可剝奪、請求與保持、循環等待。

為了預防死鎖,我們可以通過破壞其中一個或多個條件來避免死鎖的發生。

1. 資源一次性分配(破壞請求與保持條件)

當一個進程申請資源時,必須一次性申請它執行所需的所有資源。如果一次申請不到,就什么也不分配,避免持有部分資源再申請其他資源。

2. 可剝奪資源(破壞不可剝奪條件)

允許系統在資源不足時,強行從某些進程中回收已分配的資源,重新分配給其他更需要的進程。

3. 資源有序分配法(破壞循環等待條件)

為所有資源編號,進程必須按編號遞增的順序申請資源。釋放時則按編號遞減順序釋放。這樣可以避免資源請求形成閉環。


二、避免死鎖

相比預防死鎖,避免死鎖不要求完全避免死鎖條件的成立,而是在每次資源分配時判斷是否安全。

銀行家算法

預防死鎖的幾種策略,會嚴重地損害系統性能。因此在避免死鎖時,要施加較弱的限制,從而獲得較滿意的系統性能。由于在避免死鎖的策略中,允許進程動態地申請資源。因而,系統在進行資源分配之前預先計算資源分配的安全性。
這是最經典的死鎖避免算法。

  • 系統在每次資源分配前,模擬本次資源分配是否會導致系統進入不安全狀態。
  • 如果安全,則分配資源;否則讓進程等待。

三、死鎖檢測

死鎖檢測是允許死鎖發生,但系統會定期檢查是否有死鎖存在,一旦檢測到就進行處理。

步驟如下:
  1. 系統記錄所有進程與資源的指定一個唯一的號碼,構建資源分配圖或等待圖。
  2. 檢查是否存在環路(循環等待)結構。
  3. 若有環路,即可判定發生了死鎖。

四、解除死鎖

當檢測到死鎖后,需要采取措施解除死鎖狀態。常見方法如下:

1. 剝奪資源

從非死鎖進程中剝奪資源分配給死鎖進程,讓后者能繼續運行,釋放資源。

2. 撤消進程
  • 終止死鎖進程或一些代價較小的進程,釋放資源。
  • 代價可以依據優先級、運行時間、完成率、業務重要性來評估。

五、避免死鎖的編程實踐

在多線程編程中(如Java、C++),我們還可以通過一些實際的編程技巧避免死鎖:

1. 加鎖順序(Lock Ordering)

確保所有線程在獲取多個鎖時,始終按照固定順序獲取。例如:線程要獲取鎖A和鎖B,必須先獲取編號小的鎖A,再獲取鎖B。

// Thread 1:
synchronized(lockA) {synchronized(lockB) {// do something}
}
// Thread 2: 也必須先獲取lockA,再獲取lockB

按照順序加鎖是一種有效的死鎖預防機制。但是,這種方式需要你事先知道所有可能會用到的鎖,并對這些鎖做適當的排序),但總有些時候是無法預知的。

2. 加鎖時限(Try Lock with Timeout)

設置鎖獲取的超時時間,如果無法在一定時間內獲取到鎖,就放棄。

if(lock.tryLock(500, TimeUnit.MILLISECONDS)) {try {// do something} finally {lock.unlock();}
} else {// 獲取鎖失敗,執行其他邏輯或重試
}

這種方式可以有效避免長時間等待。

3. 死鎖檢測機制

針對上面兩種不適用的場景。那些不可能實現按序加鎖并且鎖超時也不可行的場景
使用數據結構記錄線程和資源的持有與請求狀態,在失敗時主動檢查是否形成了等待環。

當檢測到環路時:

  • 某些線程主動釋放鎖雖然有回退和等待,但是如果有大量的線程競爭同一批鎖,它們還是會重復地死鎖,原因同超時類似,不能從根本上減輕競爭
  • 或者優先級較低的線程撤退一段時間再重試

這種方式適合無法提前安排加鎖順序的復雜應用場景。


總結

方法是否允許死鎖發生是否易于實現是否影響性能
預防死鎖較簡單
避免死鎖
死鎖檢測
解除死鎖復雜低(只在死鎖發生時影響)

🧪真實驅動例子:互斥訪問設備寄存器

假設我們要編寫一個字符設備驅動,多個進程可能并發調用 read() 操作,訪問同一片寄存器區域。

臨界區:

static DEFINE_SPINLOCK(my_lock);ssize_t my_read(struct file *file, char __user *buf, size_t len, loff_t *off) {unsigned long flags;spin_lock_irqsave(&my_lock, flags);// 臨界區:訪問共享寄存器data = ioread32(dev->reg_base);spin_unlock_irqrestore(&my_lock, flags);return 0;
}

注意:用 spin_lock_irqsave 是因為中斷中也可能調用,必須禁止中斷防止死鎖!


🧠Q&A 常見問題

Q:單核CPU還需要加鎖嗎?
A:需要!因為即使單核,操作系統依然可以通過搶占調度讓線程切換,導致共享變量被多個線程交叉訪問。

Q:信號量可以用在中斷中嗎?
A:不能!因為信號量可能會休眠,而中斷處理函數不能休眠,否則整個中斷系統會掛死。

Q:spin_lock能不能睡眠?
A:不能!因為它禁止搶占,如果睡眠,系統可能無法調度其他任務,導致死鎖。


?總結

  • 多線程 + 共享資源 = 必須互斥
  • 自旋鎖適合臨界區非常短的場景;信號量適合長時間、可睡眠的場景
  • 死鎖問題復雜,要盡量規避:統一加鎖順序、設置超時、圖算法檢測
  • 在驅動中使用鎖時要特別考慮上下文(中斷/進程)和是否可休眠

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

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

相關文章

Kafka 架構設計和組件介紹

什么是Apache Kafka? Apache Kafka 是一個強大的開源分布式事件流平臺。它最初由 LinkedIn 開發,最初是一個消息隊列,后來發展成為處理各種場景數據流的工具。 Kafka 的分布式系統架構支持水平擴展,使消費者能夠按照自己的節奏檢…

elk中kibana一直處于可用和降級之間且es群集狀態并沒有問題的解決方法

前言 在公司部elk的時候發現kibana的web界面一直很卡,數據量為0也會很卡,es群集狀態正常,資源足夠。 報錯信息 [2025-03-17T09:54:50.19400:00][INFO ][status] Kibana is now available (was degraded) [2025-03-17T09:55:03.28000:00][I…

什么是視頻上墻

視頻聯動上墻是指當監控系統中出現報警或其他特定事件時,相關的視頻畫面能夠自動切換并顯示在指定的監控大屏或顯示設備上,以便監控人員能夠快速、直觀地查看事件現場的情況,及時做出響應和處理。 具體介紹? 系統組成 :一般由前端…

26考研——存儲系統(3)

408答疑 文章目錄 一、存儲器概述二、主存儲器三、主存儲器與 CPU 的連接四、外部存儲器五、高速緩沖存儲器六、虛擬存儲器七、參考資料鮑魚科技課件26王道考研書 八、總結復習提示思考題常見問題和易混淆知識點 一、存儲器概述 文章鏈接: 點擊跳轉 二、主存儲器 文章鏈接: …

.NET 6 + Dapper + User-Defined Table Type

大家都知道,對于SQL Server IN是有限制條件的,如果IN里面的內容過多,在執行的時候會被自動截斷,因而導致查詢到的結果不是實際需要的結果。 select * from Payments where Id in (1,2,3,4,...) 為了解決上面的限制,可以…

MySQL 8(Ubuntu 18.04.6 LTS)安裝筆記

一、前言 其實之前已經寫過一篇筆記【MySQL 8.0.34(x64)安裝筆記】。機緣巧合,這次遇到的環境是Ubuntu 18.04 LTS,相比Windows平臺的安裝,對mysql的版本以及依賴的選擇,稍微要窄一些。特作筆記。 二、準備…

學習 Apache Kafka

學習 Apache Kafka 是一個很好的選擇,尤其是在實時數據流處理和大數據領域。以下是一個系統化的學習建議,幫助你從入門到進階掌握 Kafka: 1. 先決條件 在開始 Kafka 之前,確保你具備以下基礎: Java 基礎:K…

使用 binlog2sql 閃回 MySQL8 數據

【說明】 MySQL服務器版本 8.0.26 mysql> SELECT version(); ----------- | version() | ----------- | 8.0.26 | -----------Python 版本 Python 3.8.10 [infuq ~]# python -V Python 3.8.10【安裝】 binlog2sql 官方地址 1.安裝 binlog2sql [infuq ~]# git clone …

JavaScript 異步編程與請求取消全指南

JavaScript 異步編程與請求取消全指南 涵蓋:同步/異步、Promise、async/await、AbortController、前后端協作 一、同步與異步 1. 同步(Synchronous) 定義:代碼按順序執行,前一步完成才能執行下一步。特點&#xff1…

永久緩存 Git 憑證

永久緩存 Git 憑證 打開終端或命令行工具。 執行以下命令,設置 Git 使用 store 憑證幫助程序: bash git config --global credential.helper store第一次執行 git pull 時輸入賬號密碼。之后,所有需要憑證的操作都將自動使用存儲的憑證&…

力扣-48.旋轉圖像

題目描述 給定一個 n n 的二維矩陣 matrix 表示一個圖像。請你將圖像順時針旋轉 90 度。 你必須在 原地 旋轉圖像&#xff0c;這意味著你需要直接修改輸入的二維矩陣。請不要 使用另一個矩陣來旋轉圖像。 class Solution { public:void rotate(vector<vector<int>…

Qt ModbusSlave多線程實踐總結

最近項目中用到了ModbusSlave&#xff0c;也就是Modbus從設備的功能&#xff0c;之前用的基本都是master設備&#xff0c;所以讀取數據啥的用單線程就行了&#xff0c;用 void WaitHelper::WaitImplByEventloop(int msec) {QEventLoop loop;QTimer::singleShot(msec, &loop…

opencv--圖像

像素(像素點) 定義&#xff1a; Pixel 是 Picture Element&#xff08;圖像元素&#xff09;的縮寫&#xff0c;是數字圖像中最小的獨立單位。每個像素代表圖像中的一個點的顏色和亮度信息。 關鍵特性&#xff1a; 顏色&#xff1a;通過不同的色彩模型&#xff08;如RGB、CMYK…

記錄學習匯編語言02+各種寄存器分類

8086cpu是十六位的 然后寄存器能存八位 所以分為高八位低八位 高八位在下面低八位在上面 從下往上讀&#xff08;從地址小的地方開始讀&#xff09; 8086cpu種有兩個和棧相關的寄存器 棧段寄存器ss&#xff08;棧頂的段寄存器&#xff09; 棧頂指針寄存器sp&#xff08;…

OpenCV 圖形API(53)顏色空間轉換-----將 RGB 圖像轉換為灰度圖像函數RGB2Gray()

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 將圖像從 RGB 色彩空間轉換為灰度。 R、G 和 B 通道值的常規范圍是 0 到 255。生成的灰度值計算方式如下&#xff1a; dst ( I ) 0.299 ? src…

(51單片機)LCD顯示數據存儲(DS1302時鐘模塊教學)(LCD1602教程)(獨立按鍵教程)(延時函數教程)(I2C總線認識)(AT24C02認識)

目錄 演示視頻&#xff1a; 源代碼 main.c LCD1602.c LCD1602.h AT24C02.c AT24C02.h Key.c Key.h I2C.c I2C.h Delay.c Delay.h 代碼解析與教程&#xff1a; Dealy模塊 LCD1602模塊 Key模塊 I2C總線模塊 AT24C02模塊 /E2PROM模塊 main模塊 演示視頻&#xff1a; E2…

電子病歷高質量語料庫構建方法與架構項目(數據遺忘篇)

引言 在人工智能與醫療健康的深度融合時代,醫療數據的價值與風險并存。跨機構和平臺的醫療數據共享對于推動醫學研究、提高診斷精度和實現個性化治療至關重要,但同時也帶來了前所未有的隱私挑戰。先進的AI技術可以從理論上去標識化的醫療掃描中重新識別個人身份,例如從MRI數…

CentOS創建swap內存

服務器版本為CentOS7 一、檢查現有 swap 空間 sudo swapon --show如果系統中沒有 swap 空間或者現有的 swap 空間不足&#xff0c;可以繼續后續步驟來創建 swap 空間。 二、創建 swap 文件&#xff08;推薦 2GB 作為示例&#xff09; sudo dd if/dev/zero of/swapfile bs1M …

在Android中如何使用Protobuf上傳協議

在 Android 中使用 Protobuf&#xff08;Protocol Buffers&#xff09;主要分為以下幾個步驟&#xff1a; ? 1. 添加 Protobuf 插件和依賴 在項目的 build.gradle&#xff08;Project 級&#xff09;文件中添加 Google 的 Maven 倉庫&#xff08;通常默認已有&#xff09;&am…

Android學習總結之ANR問題

一、ANR 基礎概念與核心原理&#xff08;必考題&#xff09; 1. 什么是 ANR&#xff1f;為什么會發生 ANR&#xff1f; 答案要點&#xff1a; 定義&#xff1a;ANR&#xff08;Application Not Responding&#xff09;即應用無響應&#xff0c;是 Android 系統檢測到主線程&…