(學習筆記-進程管理)怎么避免死鎖?

死鎖的概念

在多線程編程中,我們為了防止多線程競爭共享資源而導致數據錯亂,都會在操作共享資源之前加上互斥鎖,只有成功獲得到鎖的線程,才能操作共享資源,獲取不到鎖的線程就只能等待,直到鎖被釋放。

那么,當兩個線程為了保護兩個不同的共享資源而使用了兩個互斥鎖,那么這兩個互斥鎖應用不當的時候,可能會造成兩個線程都在等待對方釋放鎖,在沒有外力的作用下,這些次線程會一直相互等待,就沒法繼續運行,這種情況就是發生了死鎖

死鎖必須同時滿足以下四個條件才會發生:

  • 互斥條件
  • 持有并等待條件
  • 不可剝奪條件
  • 環路等待條件

互斥條件

互斥條件式指多個線程不能同時使用同一個資源

eg:如果線程A已經持有的資源,不能同時被線程B持有,如果線程B請求獲取線程A已經占用的資源,那線程B只能等待,直到線程A釋放了資源。

?持有并等待條件

持有并等待條件是指,當線程 A 已經持有了資源 1 ,又想申請資源 2 ,而資源 2 已經被線程 C 持有了,所以線程 A 就會處于等待狀態,但是線程 A 在等待資源 2 的同時并不會釋放在自己已經持有的資源 1

不可剝奪條件

不可剝奪條件是指,當線程已經持有了資源,在自己使用完之前不能被其他線程獲取,線程 B 如果也想使用此資源,則只能在線程 A 使用完并釋放后才能獲取。

環路等待條件

環路等待條件是指,在死鎖發生的時候,兩個線程獲取資源的順序構成了環形鏈


模擬死鎖問題的產生

用代碼來模擬死鎖問題的產生。

首先,我們創建 2 個線程,分別為線程A和線程B,然后有兩個互斥鎖,分別是 mutex_A 和 mutex_B,代碼如下:

pthread_mutex_t mutex_A = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex_B = PTHREAD_MUTEX_INITIALIZER;int main()
{pthread_t tidA, tidB;//創建兩個線程pthread_create(&tidA, NULL, threadA_proc, NULL);pthread_create(&tidB, NULL, threadB_proc, NULL);pthread_join(tidA, NULL);pthread_join(tidB, NULL);printf("exit\n");return 0;
}

線程A函數:

//線程函數 A
void *threadA_proc(void *data)
{printf("thread A waiting get ResourceA \n");pthread_mutex_lock(&mutex_A);printf("thread A got ResourceA \n");sleep(1);printf("thread A waiting get ResourceB \n");pthread_mutex_lock(&mutex_B);printf("thread A got ResourceB \n");pthread_mutex_unlock(&mutex_B);pthread_mutex_unlock(&mutex_A);return (void *)0;
}

可以看到,線程A函數的過程:

  • 先獲取互斥鎖 A ,然后睡眠 1 秒
  • 再獲取互斥鎖 B ,然后釋放互斥鎖 B
  • 最后釋放互斥鎖 A
//線程函數 B
void *threadB_proc(void *data)
{printf("thread B waiting get ResourceB \n");pthread_mutex_lock(&mutex_B);printf("thread B got ResourceB \n");sleep(1);printf("thread B waiting  get ResourceA \n");pthread_mutex_lock(&mutex_A);printf("thread B got ResourceA \n");pthread_mutex_unlock(&mutex_A);pthread_mutex_unlock(&mutex_B);return (void *)0;
}

可以看到,線程B函數的過程:

  • 先獲取互斥鎖 B ,然后睡眠 1 秒
  • 再獲取互斥鎖 A,然后釋放互斥鎖 A
  • 最后釋放互斥鎖 B

然后運行這個程序。結果如下:

thread B waiting get ResourceB 
thread B got ResourceB 
thread A waiting get ResourceA 
thread A got ResourceA 
thread B waiting get ResourceA 
thread A waiting get ResourceB 
// 阻塞中。

可以看到線程 B 在等待互斥鎖 A 的釋放,線程 A 在等待互斥鎖 B 的釋放,雙方都在等待對方資源的釋放 -> 產生了死鎖。


避免死鎖問題的發生

前面說到,產生死鎖的四個必要條件是:互斥條件、持有并等待條件、不可剝奪條件、環路等待條件。

那么避免死鎖問題就只需要破壞其中一個條件就可以,最常見的并且可行的就是使用資源有序分配法,來破壞環路等待條件

資源有序分配法:

線程 A 和線程 B 獲取資源的順序要一樣,當線程 A 是先嘗試獲取資源 A ,然后嘗試獲取資源 B 的時候,線程 B 同樣也是先嘗試獲取資源A ,然后嘗試獲取資源 B 。也就是說,線程 A 和 線程 B 總是以相同的順序申請自己想要的資源

我們使用資源有序分配法的方式來修改前面發生死鎖的代碼,我們可以不改動線程 A 的代碼。

我們先要清楚線程 A 獲取資源的順序,它是先獲取互斥鎖 A ,然后獲取互斥鎖 B。

所以我們只需要將線程B改成以相同順序的獲取資源,就可以打破死鎖了。

?線程 B 函數改進后的代碼如下:

//線程 B 函數,同線程 A 一樣,先獲取互斥鎖 A,然后獲取互斥鎖 B
void *threadB_proc(void *data)
{printf("thread B waiting get ResourceA \n");pthread_mutex_lock(&mutex_A);printf("thread B got ResourceA \n");sleep(1);printf("thread B waiting  get ResourceB \n");pthread_mutex_lock(&mutex_B);printf("thread B got ResourceB \n");pthread_mutex_unlock(&mutex_B);pthread_mutex_unlock(&mutex_A);return (void *)0;
}

總結

簡單來說,死鎖問題的產生是由兩個或者以上線程并行執行的時候,爭奪資源而互相等待造成的。

死鎖只有同時滿足互斥、持有并等待、不可剝奪、環路等待這四個條件的時候才會發生。

所以要避免死鎖問題,就是要破壞其中一個條件即可,最常用的方法就是使用資源有序分配法來破壞環路等待條件。

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

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

相關文章

創建一個簡單的HTML Viewer應用程序

使用wxPython和內嵌瀏覽器來創建一個簡單的HTML Viewer應用程序。 在本篇文章中,我們將使用Python和wxPython模塊來創建一個簡單的HTML Viewer應用程序。這個應用程序可以讓用戶輸入HTML內容,并在內嵌瀏覽器中顯示該內容的效果。 準備工作 在開始之前…

apache doris和StarRocks的區別

記錄一下最新要用到2個新數據庫的區別 Apache Doris是一個分布式的列式存儲系統,它的設計目標是提供大規模數據處理的可靠性和高性能。Doris采用了集群方式,通過將數據分布在多個機器上進行處理來提高性能,并提供了SQL查詢接口方便用戶使用。…

QT:定時器事件

定時器第一種辦法: 1.利用事件timerEvent,在幫助文檔中找到該字段:[override virtual protected] void QTimer::timerEvent(QTimerEvent *e) 重寫該虛函數 //重寫定時器事件void timerEvent(QTimerEvent *e);2.啟動定時器startTimer(1000); …

區間預測 | MATLAB實現QRGRU門控循環單元分位數回歸時間序列區間預測

區間預測 | MATLAB實現QRGRU門控循環單元分位數回歸時間序列區間預測 目錄 區間預測 | MATLAB實現QRGRU門控循環單元分位數回歸時間序列區間預測效果一覽基本介紹模型描述程序設計參考資料 效果一覽 基本介紹 MATLAB實現QRGRU門控循環單元分位數回歸時間序列區間預測。基于分位…

卷積神經網絡教程 (CNN) – 使用 TensorFlow 在 Python 中開發圖像分類器

在這篇博客中,讓我們討論什么是卷積神經網絡 (CNN) 以及 卷積神經網絡背后的架構——旨在解決 圖像識別系統和分類問題。 卷積神經網絡在圖像和視頻識別、推薦系統和自然語言處理方面有著廣泛的應用。 目錄 計算機如何讀取圖像? 為什么不是全連接網絡?

[GitOps]微服務版本控制:使用ArgoCD 部署Grafana Loki

背景介紹 請回答:你們是如何保證線上部署的服務,從服務版本到參數配置,都是和測試通過的版本是一致的呢? 本文將介紹GitOps的基本原理以及ArgoCD的使用:ArgoCD部署Grafana Loki 到k8s集群。 本文項目地址&#xff1…

詳細介紹如何使用 OpenCV 對圖像進行銳化

將了解銳化圖像的過程,我們將使用內核來突出顯示每個特定像素并增強其發出的顏色。它與模糊過程非常相似,只不過現在我們不是創建一個內核來平均每個像素強度,而是創建一個內核,該內核將使像素強度更高,因此對人眼來說更加突出。 了解流程的后端。 很高興知道內核用于模糊…

Nginx 解決api跨域問題

環境: nginx 1.22.1 寶塔8.0 php lavarel 在nginx里加入下面的設置 #這里填*就是任何域名都允許跨域add_header Access-Control-Allow-Origin "*";#CORS請求默認不發送Cookie和HTTP認證信息。但是如果要把Cookie發到服務器,要服務器同意&#xff0c…

Webpack和Parcel詳解

構建工具和打包器是在開發過程中幫助組織、優化和打包項目的工具。它們可以處理依賴管理、資源優化、代碼轉換等任務,從而使開發流程更高效。以下是關于構建工具和打包器的一些指導: **Webpack:** Webpack 是一個功能強大的模塊打包器&#…

Java“牽手”1688商品詳情頁面數據獲取方法,1688API實現批量商品數據抓取示例

背景:1688商城是一個網上購物平臺,售賣各類商品,包括服裝、鞋類、家居用品、美妝產品、電子產品等。要獲取1688商品詳情數據,您可以通過開放平臺的接口或者直接訪問1688商城的網頁來獲取商品詳情信息。以下是兩種常用方法的介紹&a…

538頁21萬字數字政府智慧政務大數據云平臺項目建設方案WORD

導讀:原文《538頁21萬字數字政府智慧政務大數據云平臺項目建設方案WORD》(獲取來源見文尾),本文精選其中精華及架構部分,邏輯清晰、內容完整,為快速形成售前方案提供參考。 根據業務的不同屬性&#xff0c…

深入解析 Axios Blob 的使用方法及技巧

在 Web 開發中,處理文件傳輸是一個常見的需求。Blob(二進制對象)是一種表示二進制數據的方式,常用于處理文件和多媒體數據。本文將介紹如何使用 Axios 和 Blob 來處理文件傳輸。 Axios Blob 概念 在開始之前,讓我們先…

IC流程中 DFT 學習筆記(1)

引言 DFT是ASIC芯片設計流程中不可或缺的環節。其主要目的是在芯片前端設計驗證完成后插入一些諸如寄存器鏈等可供測試的邏輯,算是IC后端設計的范疇。主要是在ASIC芯片流片完成后,通過這些已插入的邏輯,檢測流片得到的芯片的制造質量。檢測一…

Go framework-Beego

一、Beego Beego用于在Go中快速開發企業應用程序,包括RESTful API、web應用程序和后端服務。 Beego 源碼地址 Beego 官方站點 Beego 官方說明 Beego的特性 RESTful支持MVC架構模塊化自動API文檔注釋路由命名空間開發工具集合Full stack for Web & API Bee…

使用provision創建的arxml文件,導入到第三方工具需要注意哪些方面?

provision是一款基于AP AUTOSAR的ARXML設計工具,可以幫助您快速創建和配置ARXML文件。 如果您想要將provision創建的ARXML文件導入到第三方工具中,您需要注意以下幾個方面: 您需要確認第三方工具支持的AP AUTOSAR版本和provision生成的ARXML…

非計算機科班如何順利轉行計算機領域?

文章目錄 每日一句正能量前言如何規劃才能實現轉計算機?計算機崗位發展前景?現階段轉計算機的建議后記 每日一句正能量 改變思路,改變習慣,改變一種活的方式,往往會創造無限,風景無限! 前言 近年…

Java并發編程(四)線程同步 中 [AQS/Lock]

概述 Java中可以通過加鎖,來保證多個線程訪問某一個公共資源時,資源的訪問安全性。Java提出了兩種方式來加鎖 第一種是我們上文提到的通過關鍵字synchronized加鎖,synchronized底層托管給JVM執行的,并且在java 1.6 以后做了很多…

一百五十二、Kettle——Kettle9.3.0本地連接Hive3.1.2(踩坑,親測有效,附截圖)

一、目的 由于先前使用的kettle8.2版本在Linux上安裝后&#xff0c;創建共享資源庫點擊connect時頁面為空&#xff0c;后來采用如下方法&#xff0c;在/opt/install/data-integration/ui/menubar.xul文件里添加如下代碼 <menuitem id"file-openZiyuanku" label&…

音視頻學習-音視頻基礎

文章目錄 一、 音視頻錄制原理二、音視頻播放原理三、圖像基礎概念1.像素2.分辨率3.位深4.幀率5.碼率6.Stride跨距 四、RGB、YUV1.RGB2.YUV1. 4:4:4格式2. 4:2:2格式3. 4:2:0格式4. 4:2:0數據格式對比 3.RGB和YUV的轉換4.YUV Stride對齊問題 五、視頻的主要概念1.基本概念2.I P…

數據結構:棧和隊列(超詳細)

目錄 ?編輯 棧&#xff1a; 棧的概念及結構&#xff1a; 棧的實現&#xff1a; 隊列&#xff1a; 隊列的概念及結構&#xff1a; 隊列的實現&#xff1a; 擴展知識&#xff1a; 以上就是個人學習線性表的個人見解和學習的解析&#xff0c;歡迎各位大佬在評論區探討&#…