死鎖 手撕死鎖檢測工具

目錄

引言

一.理論聯立

1.死鎖的概念和原因

2.死鎖檢測的基本思路

?

3.有向圖在死鎖檢測中的應用

二.代碼實現案例(我們會介紹部分重要接口解釋)

1.我們定義一個線性表來存線程ID和鎖ID

2.表中數據的查詢接口

3.表中數據的刪除接口

4.表中數據的添加接口

5.before_lock接口

6.afterlock接口

7.after_unlock接口

8.加鎖和解鎖的接口

9.檢測死鎖的接口

三.結果展示


?

引言

死鎖是指在計算機系統中,多個進程(或線程)因競爭資源而造成的一種僵局,若無外力作用,這些進程(或線程)都將無法向前推進

我們將基于多個線程和多個互斥鎖來介紹死鎖的長生

?

一.理論聯立

1.死鎖的概念和原因

①.死鎖是操作系統和學術概念,指線程占用資源導致互相等待對方釋放資源的情況。

②.死鎖常見于多線程環境中,導致CPU占用率100%,出現死循環。

圖中有線程A,線程B,和線程C 三個線程 它們各自擁有自己各自的資源的情況下?其中

線程A想占用線程B的資源

線程B 想占用線程C的資源

線程C想占用線程A的資源?

最后形成了一個環 最后導致了死鎖

2.死鎖檢測的基本思路

①.死鎖檢測依賴于資源占用情況的檢測,通過判斷是否構成環來實現。

②.環的構成表示線程間形成了死鎖。

?

3.有向圖在死鎖檢測中的應用

①.有向圖是否成環的問題是死鎖檢測的底層算法。

②.通過有向圖來判斷是否構成環,從而檢測死鎖。

③.有向圖的構建通過節點和邊來表示線程和資源的關系。

④.環的檢測通過深度優先搜索(DFS)來實現。

?

?

?

二.代碼實現案例(我們會介紹部分重要接口解釋)

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#define _GNU_SOURCE
#include <dlfcn.h>
#include<stdlib.h>#define MAX		100typedef unsigned long int uint64;struct rela_node{pthread_mutex_t *mtx;pthread_t thid;
};struct rela_node rela_table[MAX]={0};//search
pthread_t search_rela_table(pthread_mutex_t*mtx){int i = 0;for(i;i<MAX;i++){if(mtx==rela_table[i].mtx){return rela_table[i].thid;}}return 0;
}//dele
int dele_rela_table(pthread_t tid,pthread_mutex_t *mtx){int i =0;for(i;i<MAX;i++){if((rela_table[i].thid==tid)&&(rela_table[i].mtx==mtx)){rela_table[i].thid=0;rela_table[i].mtx=NULL;return 0;}}return -1;
}//add
int add_rela_table(pthread_t tid,pthread_mutex_t *mtx){int i =0;for(i;i<MAX;i++){if((rela_table[i].thid==0)&&(rela_table[i].mtx==NULL)){rela_table[i].thid=tid;rela_table[i].mtx=mtx;return 0;}}return -1;
}#if 1  
//有向圖
enum Type {PROCESS, RESOURCE};struct source_type {uint64 id;enum Type type;uint64 lock_id;int degress;
};struct vertex {struct source_type s;struct vertex *next;};struct task_graph {struct vertex list[MAX];int num;struct source_type locklist[MAX];int lockidx; //pthread_mutex_t mutex;
};struct task_graph *tg = NULL;
int path[MAX+1];
int visited[MAX];
int k = 0;
int deadlock = 0;struct vertex *create_vertex(struct source_type type) {struct vertex *tex = (struct vertex *)malloc(sizeof(struct vertex ));tex->s = type;tex->next = NULL;return tex;}int search_vertex(struct source_type type) {int i = 0;for (i = 0;i < tg->num;i ++) {if (tg->list[i].s.type == type.type && tg->list[i].s.id == type.id) {return i;}}return -1;
}void add_vertex(struct source_type type) {if (search_vertex(type) == -1) {tg->list[tg->num].s = type;tg->list[tg->num].next = NULL;tg->num ++;}}int add_edge(struct source_type from, struct source_type to) {add_vertex(from);add_vertex(to);struct vertex *v = &(tg->list[search_vertex(from)]);while (v->next != NULL) {v = v->next;}v->next = create_vertex(to);}int verify_edge(struct source_type i, struct source_type j) {if (tg->num == 0) return 0;int idx = search_vertex(i);if (idx == -1) {return 0;}struct vertex *v = &(tg->list[idx]);while (v != NULL) {if (v->s.id == j.id) return 1;v = v->next;}return 0;}int remove_edge(struct source_type from, struct source_type to) {int idxi = search_vertex(from);int idxj = search_vertex(to);if (idxi != -1 && idxj != -1) {struct vertex *v = &tg->list[idxi];struct vertex *remove;while (v->next != NULL) {if (v->next->s.id == to.id) {remove = v->next;v->next = v->next->next;free(remove);break;}v = v->next;}}}void print_deadlock(void) {int i = 0;printf("cycle : ");for (i = 0;i < k-1;i ++) {printf("%ld --> ", tg->list[path[i]].s.id);}printf("%ld\n", tg->list[path[i]].s.id);}int DFS(int idx) {struct vertex *ver = &tg->list[idx];if (visited[idx] == 1) {path[k++] = idx;print_deadlock();deadlock = 1;return 0;}visited[idx] = 1;path[k++] = idx;while (ver->next != NULL) {DFS(search_vertex(ver->next->s));k --;ver = ver->next;}return 1;}int search_for_cycle(int idx) {struct vertex *ver = &tg->list[idx];visited[idx] = 1;k = 0;path[k++] = idx;while (ver->next != NULL) {int i = 0;for (i = 0;i < tg->num;i ++) {if (i == idx) continue;visited[i] = 0;}for (i = 1;i <= MAX;i ++) {path[i] = -1;}k = 1;DFS(search_vertex(ver->next->s));ver = ver->next;}}int init_graph(void){tg=(struct task_graph*)malloc(sizeof(struct task_graph));tg->num=0;
}#endifvoid before_lock(pthread_t tid,pthread_mutex_t*mtx){pthread_t otherid=search_rela_table(mtx);if(otherid!=0){//mtx有線程在占用struct source_type from;from.id=tid;from.type=PROCESS;struct source_type to;to.id=otherid;to.type=PROCESS;add_edge(from,to);}}//如果走到after_lock 則表明mtx沒有被線程占用 把之前的邊刪除 然后我們占用該mtx
void after_lock(pthread_t tid,pthread_mutex_t*mtx){pthread_t otherid=search_rela_table(mtx);if(otherid!=0){//刪除舊邊struct source_type from;from.id=tid;from.type=PROCESS;struct source_type to;to.id=otherid;to.type=PROCESS;if(verify_edge(from,to)){remove_edge(from,to);}}//mtx無線程在占用 則占我們占用add_rela_table(tid,mtx);
}
void after_unlock(pthread_t tid,pthread_mutex_t*mtx){dele_rela_table(tid,mtx);//有小問題 這個死鎖工具可能只能檢測一次 如果存在解鎖情況 可能會導致after_lock mtx找不到舊線程id
}//檢測死鎖
void check_dead_lock(void){int i =0;for(i;i<tg->num;i++){search_for_cycle(i);}
}static void *thread_routine(void*arg){while(1){sleep(5);check_dead_lock();}
}
void start_check(void) {pthread_t tid;pthread_create(&tid, NULL, thread_routine, NULL);}#if 1  //hook
typedef int (*pthread_mutex_lock_t)(pthread_mutex_t*mtx);
pthread_mutex_lock_t pthread_mutex_lock_f=NULL;typedef int (*pthread_mutex_unlock_t)(pthread_mutex_t*mtx);
pthread_mutex_unlock_t pthread_mutex_unlock_f=NULL;typedef int (*pthread_create_t)(pthread_t *restrict thread, const pthread_attr_t *restrict attr,void *(*start_routine)(void *), void *restrict arg);
pthread_create_t pthread_create_f = NULL;int pthread_mutex_lock(pthread_mutex_t*mtx){// printf("before pthread_mutex_lock%ld,%p \n",pthread_self(),mtx);pthread_t selfid = pthread_self();before_lock(selfid, mtx);pthread_mutex_lock_f(mtx);// printf("after pthread_mutex_lock\n");after_lock(selfid,mtx);
}int pthread_mutex_unlock(pthread_mutex_t*mtx){pthread_t selfid = pthread_self();pthread_mutex_unlock_f(mtx);after_unlock(selfid,mtx);// printf("after pthread_mutex_unlock%ld,%p \n",pthread_self(),mtx);}int pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr,void *(*start_routine)(void *), void *restrict arg) {pthread_create_f(thread,attr,start_routine,arg);struct source_type v1;v1.id=*thread;v1.type=PROCESS;add_vertex(v1);
}void init_hook(void){if(!pthread_mutex_lock_f){pthread_mutex_lock_f = dlsym(RTLD_NEXT,"pthread_mutex_lock");}if(!pthread_mutex_unlock_f){pthread_mutex_unlock_f = dlsym(RTLD_NEXT,"pthread_mutex_unlock");}if (!pthread_create_f) {pthread_create_f = dlsym(RTLD_NEXT, "pthread_create");}}
#endif#if 1//debug
pthread_mutex_t mtx1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mtx2 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mtx3 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mtx4 = PTHREAD_MUTEX_INITIALIZER;void * t1_cb(void*arg){printf("pid1=%ld\n",pthread_self());pthread_mutex_lock(&mtx1);sleep(1);pthread_mutex_lock(&mtx2);pthread_mutex_unlock(&mtx2);pthread_mutex_unlock(&mtx1);}
void * t2_cb(void*arg){printf("pid2=%ld\n",pthread_self());pthread_mutex_lock(&mtx2);sleep(1);pthread_mutex_lock(&mtx3);pthread_mutex_unlock(&mtx3);pthread_mutex_unlock(&mtx2);}void * t3_cb(void*arg){printf("pid3=%ld\n",pthread_self());pthread_mutex_lock(&mtx3);sleep(1);pthread_mutex_lock(&mtx4);pthread_mutex_unlock(&mtx4);pthread_mutex_unlock(&mtx3);
}void * t4_cb(void*arg){printf("pid4=%ld\n",pthread_self());pthread_mutex_lock(&mtx4);sleep(1);pthread_mutex_lock(&mtx1);pthread_mutex_unlock(&mtx1);pthread_mutex_unlock(&mtx4);
}
int main(){init_graph();//有向圖的初始化init_hook();//hook函數的初始化pthread_t t1,t2,t3,t4;start_check();//開始檢測死鎖pthread_create(&t1,NULL,t1_cb,NULL);pthread_create(&t2,NULL,t2_cb,NULL);pthread_create(&t3,NULL,t3_cb,NULL);pthread_create(&t4,NULL,t4_cb,NULL);pthread_join(t1,NULL);pthread_join(t2,NULL);pthread_join(t3,NULL);pthread_join(t4,NULL);printf("complete\n");
}
#endif

具體代碼接口的實現

1.我們定義一個線性表來存線程ID和鎖ID

typedef unsigned long int uint64;struct rela_node{pthread_mutex_t *mtx;pthread_t thid;
};struct rela_node rela_table[MAX]={0};

2.表中數據的查詢接口

//search
pthread_t search_rela_table(pthread_mutex_t*mtx){int i = 0;for(i;i<MAX;i++){if(mtx==rela_table[i].mtx){return rela_table[i].thid;}}return 0;
}

?

3.表中數據的刪除接口

//dele
int dele_rela_table(pthread_t tid,pthread_mutex_t *mtx){int i =0;for(i;i<MAX;i++){if((rela_table[i].thid==tid)&&(rela_table[i].mtx==mtx)){rela_table[i].thid=0;rela_table[i].mtx=NULL;return 0;}}return -1;
}

4.表中數據的添加接口

//add
int add_rela_table(pthread_t tid,pthread_mutex_t *mtx){int i =0;for(i;i<MAX;i++){if((rela_table[i].thid==0)&&(rela_table[i].mtx==NULL)){rela_table[i].thid=tid;rela_table[i].mtx=mtx;return 0;}}return -1;
}

?

5.before_lock接口

void before_lock(pthread_t tid,pthread_mutex_t*mtx){pthread_t otherid=search_rela_table(mtx);if(otherid!=0){//mtx有線程在占用struct source_type from;from.id=tid;from.type=PROCESS;struct source_type to;to.id=otherid;to.type=PROCESS;add_edge(from,to);}}

我們傳入當前線程id和鎖

我們先對鎖進行判斷是否有線程在占用 如果有線程在占用我們則和該線程建立一條邊

6.afterlock接口

//如果走到after_lock 則表明mtx沒有被線程占用 把之前的邊刪除 然后我們占用該mtx
void after_lock(pthread_t tid,pthread_mutex_t*mtx){pthread_t otherid=search_rela_table(mtx);if(otherid!=0){//刪除舊邊struct source_type from;from.id=tid;from.type=PROCESS;struct source_type to;to.id=otherid;to.type=PROCESS;if(verify_edge(from,to)){remove_edge(from,to);}}//mtx無線程在占用 則占我們占用add_rela_table(tid,mtx);
}

我們要先判斷該鎖之前是否和其他線程建立邊 如果有我們就刪除舊邊 然后占用該把鎖

7.after_unlock接口

void after_unlock(pthread_t tid,pthread_mutex_t*mtx){dele_rela_table(tid,mtx);//有小問題 這個死鎖工具可能只能檢測一次 如果存在解鎖情況 可能會導致after_lock mtx找不到舊線程id
}

8.加鎖和解鎖的接口

int pthread_mutex_lock(pthread_mutex_t*mtx){// printf("before pthread_mutex_lock%ld,%p \n",pthread_self(),mtx);pthread_t selfid = pthread_self();before_lock(selfid, mtx);pthread_mutex_lock_f(mtx);// printf("after pthread_mutex_lock\n");after_lock(selfid,mtx);
}int pthread_mutex_unlock(pthread_mutex_t*mtx){pthread_t selfid = pthread_self();pthread_mutex_unlock_f(mtx);after_unlock(selfid,mtx);// printf("after pthread_mutex_unlock%ld,%p \n",pthread_self(),mtx);}

9.檢測死鎖的接口

//檢測死鎖
void check_dead_lock(void){int i =0;for(i;i<tg->num;i++){search_for_cycle(i);}
}static void *thread_routine(void*arg){while(1){sleep(5);check_dead_lock();}
}
void start_check(void) {pthread_t tid;pthread_create(&tid, NULL, thread_routine, NULL);}

?

三.結果展示

?

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

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

相關文章

Java 中 SQL 注入問題剖析?

一、引言? 在當今數字化時代&#xff0c;數據是企業和組織的核心資產之一。許多應用程序都依賴于數據庫來存儲和管理數據&#xff0c;而 Java 作為一種廣泛使用的編程語言&#xff0c;常被用于開發與數據庫交互的應用程序。然而&#xff0c;SQL 注入這一安全漏洞卻如同隱藏在…

安全理念和安全產品發展史

從安全理念的發展歷史來看,技術與產品的演進始終圍繞 “威脅對抗” 與 “業務適配” 兩大核心展開。以下從七個關鍵階段解析安全技術與產品的發展脈絡,并結合最新實踐與未來趨勢提供深度洞察: 一、密碼學奠基階段(1970s 前) 安全理念:以 “信息保密” 為核心,防御手段…

【Ansible自動化運維】二、Playbook 深入探究:構建復雜自動化流程

? 在 Ansible 自動化運維體系中&#xff0c;Playbook 是極為關鍵的部分。它允許我們以一種結構化、可重復的方式定義和執行一系列復雜的任務&#xff0c;從而構建高效的自動化流程。本篇文章將深入探究 Ansible Playbook 的各個方面&#xff0c;助您掌握構建復雜自動化…

springboot項目中常用的工具類和api

在Spring Boot項目中&#xff0c;開發者通常會依賴一些工具類和API來簡化開發、提高效率。以下是一些常用的工具類及其典型應用場景&#xff0c;涵蓋 Spring 原生工具、第三方庫&#xff08;如Hutool、Guava&#xff09; 和 Java 自帶工具。 1. Spring Framework 自帶工具類 (…

23種設計模式-行為型模式-模板方法

文章目錄 簡介場景解決代碼關鍵優化點 總結 簡介 模板方法是一種行為設計模式&#xff0c;它在超類中定義了一個算法的框架&#xff0c;允許子類在不修改結構的情況下重寫算法的特定步驟。 場景 假如你正在開發一款分析文檔的數據挖掘程序。用戶需要向程序輸入各種格式&…

解決Long類型前端精度丟失和正常傳回后端問題

在 Java 后端開發中&#xff0c;可能會遇到前后端交互過程中 Long 類型精度丟失的問題。尤其是在 JavaScript 中&#xff0c;由于其 Number 類型是雙精度浮點數&#xff0c;超過 16 位的 Long 類型值就會發生精度丟失。 問題背景 假設有如下實體類&#xff1a; public class…

PowerPhotos:拯救你的Mac照片庫,告別蘋果原生應用的局限

如果你用Mac管理照片&#xff0c;大概率被蘋果原生「照片」應用折磨過——無法真正并行操作多個圖庫。每次切換圖庫都要關閉重啟&#xff0c;想合并照片得手動導出導入&#xff0c;重復文件更是無處可逃…… 直到我發現了 PowerPhotos&#xff0c;這款專為Mac設計的照片庫管理…

android 14.0 工廠模式 測試音頻的一些問題(高通)

1之前用tinycap&#xff0c;現在得用agmcap 執行----agmcap /data/test.wav -D 100 -d 101 -i CODEC_DMA-LPAIF_RXTX-TX-3 -T 3 報錯1 agmcap data/test.wav -D 100 -d 101 -i CODEC_DMA-LPAIF_RXTX-TX-3 -T 3 Failed to open xml file name /vendor/etc/backend_co…

以庫存系統為核心的ERP底層架構設計

在企業資源計劃&#xff08;ERP&#xff09;系統中&#xff0c;庫存系統常被視為基礎模塊。但在現代企業的數字化進程中&#xff0c;庫存系統不僅僅是一個模塊&#xff0c;它已經逐步演化為驅動整個ERP生態的核心引擎。本文從架構設計的角度&#xff0c;探討為何庫存系統應被置…

辛格迪客戶案例 | 北京舒曼德醫藥實施電子合約系統(eSign)

01 北京舒曼德醫藥科技開發有限公司&#xff1a;醫藥科技的數字化先鋒 北京舒曼德醫藥科技開發有限公司&#xff08;以下簡稱“舒曼德醫藥”&#xff09;作為國內醫藥科技領域的領軍企業&#xff0c;致力于創新藥物的研發、臨床試驗和市場推廣。公司以“科技興藥、質量為先、服…

【UE5】RTS游戲的框選功能+行軍線效果實現

目錄 效果 步驟 一、項目準備 二、框選NPC并移動到指定地點 三、框選效果 效果 步驟 一、項目準備 1. 新建一個俯視角游戲工程 2. 新建一個pawn、玩家控制器和游戲模式,這里分別命名為“MyPawn”、“MyController”和“MyGameMode” 3. 打開“MyGameMode”,設置玩家…

vim定位有問題的腳本/插件的一般方法

在使用vim的過程中可能會遇到一些報錯或其他不符合預期的情況&#xff0c;本文介紹一些我自己常用的定位有問題腳本/插件的方法&#xff08;以下方法同樣適用于neovim&#xff09; 執行了某些命令的情況 這種情況最簡單&#xff0c;使用:h 命令&#xff0c;如果插件有文檔的話…

智能驅動教育變革:人工智能在高中教育中的實踐路徑與創新策略

一、引言 隨著信息技術的飛速發展&#xff0c;人工智能&#xff08;Artificial Intelligence, AI&#xff09;已成為推動社會進步的重要力量。在教育領域&#xff0c;人工智能的應用正逐漸改變著傳統的教學模式和方法&#xff0c;為教育現代化注入了新的活力。高中教育作為教育…

VLAN(虛擬局域網)

一、vlan概述 VLAN(virtual local area network)是一種通過邏輯方式劃分網絡的技術&#xff0c;允許將一個物理網絡劃分為多個獨立的虛擬網絡。每一個vlan是一個廣播域&#xff0c;不同vlan之間的通信需要通過路由器或三層交換機 [!注意] vlan是交換機獨有的技術&#xff0c;P…

spring-cloud-starter-alibaba-seata使用說明

Spring Cloud Alibaba Seata 使用說明 spring-cloud-starter-alibaba-seata 是 Spring Cloud Alibaba 生態中用于集成分布式事務框架 Seata 的核心組件&#xff0c;支持 AT&#xff08;自動補償&#xff09;、TCC&#xff08;手動補償&#xff09; 等模式。 一、依賴配置 添加…

每日一題(小白)暴力娛樂篇23

由題意得知給我們一串數字&#xff0c;我們每次交換兩位&#xff0c;最少交換多少次成功得到有順序的數組。我們以平常的思維去思考&#xff0c;加入給你一串數字獲得最少的交換次數&#xff0c;意味著你的交換后續基本不會變&#xff0c;比如說2 1 3 5 4 中1與2交換后不變&…

Python基礎——Pandas庫

對象的創建 導入 Pandas 時&#xff0c;通常給其一個別名“pd”&#xff0c;即 import pandas as pd。作為標簽庫&#xff0c;Pandas 對象在 NumPy 數組基礎上給予其行列標簽。可以說&#xff0c;列表之于字典&#xff0c;就如 NumPy 之于 Pandas。Pandas 中&#xff0c;所有數…

Spring入門概念 以及入門案例

Spring入門案例 Springspring是什么spring的狹義與廣義spring的兩個核心模塊IoCAOP Spring framework特點spring入門案例不用new方法&#xff0c;如何使用返回創建的對象 容器&#xff1a;IoC控制反轉依賴注入 Spring spring是什么 spring是一款主流的Java EE輕量級開源框架 …

The packaging for this project did not assign a file to the build artifact

問題&#xff1a; maven install報錯&#xff1a;The packaging for this project did not assign a file to the build artifact 解決方案&#xff1a; 方案1&#xff1a; 使用mvn clean install 就可以解決問題&#xff0c; 方案2&#xff1a; 找到lifecycle點clean再點…

C++入門一:C++ 編程概述

一、C 語言與 C 的關系&#xff1a;從 “帶類的 C” 到獨立王國 1.1 血緣關系&#xff1a;C 是 C 的 “超級進化版” 起源&#xff1a;C 由 Bjarne Stroustrup 在 1980 年代開發&#xff0c;最初名為 “C with Classes”&#xff08;帶類的 C&#xff09;&#xff0c;旨在為 …