死锁原因及死锁检测组件的实现

news2024/11/22 20:56:02

1 死锁形成的条件

  死锁,是指多个线程或者进程在运行过程中因争夺有限的系统资源而造成的一种僵局,当进程或者线程处于这种僵持状态,若无外力作用,它们将无法再向前推进。如下图所示,线程 A 想获取线
程 B 的锁,线程 B 想获取线程 C 的锁,线程 C 想获取线程 D 的锁,线程 D 想获取线程 A 的。
锁,从而构建了一个资源获取环。  
死锁的存在是因为有资源获取环的存在,所以只要能检测出资源获取环,就等同于检测出
死锁的存在。

 

2.死锁检测原理

死锁检测是计算机系统中的关键组件,用于检测和解决死锁问题,确保系统的正常运行。死锁检测组件的实现原理通常包括以下几个关键步骤:

1. 资源分配图构建:死锁检测通常基于资源分配图来进行。资源分配图是一个有向图,其中节点表示进程和资源,边表示资源的分配关系和请求关系。每个进程和资源都有对应的节点,并且有向边表示进程请求资源和释放资源的行为。

2. 图转化:将资源分配图转化为一种更容易分析的数据结构,通常是一个等待图(Wait-For Graph)或资源分配矩阵。等待图是资源分配图的简化版本,其中只包括等待关系。资源分配矩阵是一个矩阵,其中行代表进程,列代表资源,元素表示资源的分配情况。

3. 检测循环:通过分析等待图或资源分配矩阵,检测是否存在环路。如果存在环路,说明可能存在死锁。这是因为环路表示一组进程之间的资源请求和释放关系,它们彼此之间形成了一个循环,使得每个进程都无法继续执行。

4. 死锁恢复:如果检测到死锁,死锁检测组件可以采取不同的措施来解决死锁。这些措施包括终止某些进程以释放资源、回滚进程的状态、或者等待资源释放。

5. 周期性检测:死锁检测组件通常会定期运行,以便随时检测潜在的死锁情况。这样可以在早期阶段识别和处理死锁,以减小对系统的影响。

需要注意的是,死锁检测虽然可以检测和解决死锁问题,但它不是最高效的方法,因为它需要定期运行,并且可能会引入一些系统开销。更好的方法是通过设计良好的算法和策略来预防死锁的发生。死锁预防的方法包括资源分配策略、资源请求顺序的规定以及进程调度策略等。这些方法有助于降低死锁的概率,从根本上减少死锁问题的发生。

3.死锁检测组件的实现

#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>

#if 1

#include <stdint.h>

typedef unsigned long int uint64;


#define MAX		100

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;
	}

}

#endif

int search_lock(uint64 lock) {

	int i = 0;
	
	for (i = 0;i < tg->lockidx;i ++) {
		
		if (tg->locklist[i].lock_id == lock) {
			return i;
		}
	}

	return -1;
}

int search_empty_lock(uint64 lock) {

	int i = 0;
	
	for (i = 0;i < tg->lockidx;i ++) {
		
		if (tg->locklist[i].lock_id == 0) {
			return i;
		}
	}

	return tg->lockidx;

}


void lock_before(uint64_t tid, uint64_t lockaddr) {
    int idx = 0;
    for(;idx < tg->lockidx; idx++) {
        if(tg->locklist[idx].lock_id == lockaddr) {
            struct source_type from;
            from.id = tid;
            from.type = PROCESS;
            add_vertex(from);

            struct source_type to;
            to.id = tg->locklist[idx].id;
            to.type = PROCESS;
            add_vertex(to);

            tg->locklist[idx].degress++;

            if(!verify_edge(from, to))
                add_edge(from, to);
        }
    }
}

void lock_after(uint64_t tid, uint64_t lockaddr) {
    int idx = 0;
    if(-1 == (idx = search_lock(lockaddr))) {
        int edix = search_empty_lock(lockaddr);
        tg->locklist[edix].id = tid;
        tg->locklist[edix].lock_id = lockaddr;
        tg->lockidx ++;
    } else{
        struct source_type from;
        from.id = tid;
        from.type = PROCESS;
        add_vertex(from);

        struct source_type to;
        to.id = tg->locklist[idx].id;
        to.type = PROCESS;
        add_vertex(to);

        tg->locklist[idx].degress --;

        if(verify_edge(from, to));
            remove_edge(from, to);

        tg->locklist[idx].id = tid;
    }
}

void unlock_after(uint64_t tid, uint64_t lockaddr) {
    int idx = search_lock(lockaddr);
    if(tg->locklist[idx].degress == 0) {
        tg->locklist[idx].id = 0;
        tg->locklist[idx].lock_id = 0;
    }
}

void check_dead_lock(void) {

	int i = 0;

	deadlock = 0;
	for (i = 0;i < tg->num;i ++) {
		if (deadlock == 1) break;
		search_for_cycle(i);
	}

	if (deadlock == 0) {
		printf("no deadlock\n");
	}

}


static void *thread_routine(void *args) {

	while (1) {

		sleep(5);
		check_dead_lock();

	}

}


void start_check(void) {

	tg = (struct task_graph*)malloc(sizeof(struct task_graph));
	tg->num = 0;
	tg->lockidx = 0;
	
	pthread_t tid;

	pthread_create(&tid, NULL, thread_routine, NULL);

}



typedef int (*pthread_mutex_lock_t)(pthread_mutex_t *mutex);
pthread_mutex_lock_t pthread_mutex_lock_f = NULL;

typedef int (*pthread_mutex_unlock_t)(pthread_mutex_t *mutex);
pthread_mutex_unlock_t pthread_mutex_unlock_f = NULL;

int pthread_mutex_lock(pthread_mutex_t *mutex) {

    pthread_t selfid = pthread_self();

    lock_before((uint64_t)selfid,(uint64_t)mutex);
    pthread_mutex_lock_f(mutex);
    lock_after((uint64_t)selfid,(uint64_t)mutex);

    //printf("[%s:%s;%d] pthread_mutex_lock selfid: %ld, %p\n", \
        __FILE__,__func__,__LINE__,selfid,mutex);
}

int pthread_mutex_unlock(pthread_mutex_t *mutex) {
    pthread_t selfid = pthread_self();

    
    pthread_mutex_unlock_f(mutex);
    unlock_after((uint64_t)selfid,(uint64_t)mutex);

    //printf("[%s:%s;%d] pthread_mutex_lock selfid: %ld, %p\n",\
        __FILE__,__func__,__LINE__,selfid,mutex);
}

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");
    }
}

/*
只需在需要检测死锁的程序中添加该文件,并且在程序的main函数中添加下面两句代码编译执行即可
init_hook();
start_check();
*/


#if 0

pthread_mutex_t r1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t r2 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t r3 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t r4 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t r5 = PTHREAD_MUTEX_INITIALIZER;

void *t1_cb(void *arg) {
    pthread_mutex_lock(&r1);
    sleep(1);
    pthread_mutex_lock(&r2);


    pthread_mutex_unlock(&r2);

    pthread_mutex_unlock(&r1);
}

void *t2_cb(void *arg) {
    pthread_mutex_lock(&r2);
    sleep(1);
    pthread_mutex_lock(&r3);
    

    pthread_mutex_unlock(&r3);

    pthread_mutex_unlock(&r2);
}

void *t3_cb(void *arg) {
    pthread_mutex_lock(&r3);
    sleep(1);
    pthread_mutex_lock(&r4);


    pthread_mutex_unlock(&r4);

    pthread_mutex_unlock(&r3);
}

void *t4_cb(void *arg) {
    pthread_mutex_lock(&r4);
    sleep(1);
#if 1
    pthread_mutex_lock(&r2);
    

    pthread_mutex_unlock(&r2);
#endif
    pthread_mutex_unlock(&r4);
}

void *t5_cb(void *arg) {
    pthread_mutex_lock(&r5);
    sleep(1);
#if 0
    pthread_mutex_lock(&r1);


    pthread_mutex_unlock(&r1);
#endif
    pthread_mutex_unlock(&r5);
}

int main(void) {
    init_hook();
    start_check();

    pthread_t t1,t2,t3,t4,t5;

    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_create(&t5, NULL,t5_cb, NULL);

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    pthread_join(t3, NULL);
    pthread_join(t4, NULL);
    pthread_join(t5, NULL);

    printf("complete\n");

    return 0;
}

#endif

通过模拟不同的死锁场景得到的结果: 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1091462.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

当你在 Tubi 是一位 Tech Lead

在过去&#xff0c;我们邀请了 Tubi 技术团队的许多资深工程师&#xff0c;听他们分享了作为资深工程师的一些故事。今天&#xff0c;我们将镜头转向那些在 Tubi 担任 Tech Lead 的工程师&#xff0c;他们选择了在独立开发之外&#xff0c;承担一定的技术管理工作&#xff1a; …

计算机网络——计算机网络体系结构(1/4)-常见的计算机网络体系结构(OSI体系、TCP/IP体系、原理体系五层协议)

目录 OSI体系结构 OSI体系介绍 OSI失败的原因 TCP/IP体系结构 TCP/IP概述 网络接口层 网际层 运输层 应用层 TCP/IP命名的由来 原理体系结构&#xff08;五层协议&#xff09; OSI体系结构 OSI体系介绍 著名的“开放系统互连参考模型”&#xff0c;简称为OSI。该模…

Windows下Qt读取系统的内存、CPU、GPU等使用信息

一、前言 在当今计算机应用广泛的领域中&#xff0c;了解系统的内存、CPU和GPU使用情况是非常重要的。对于开发人员和系统管理员来说&#xff0c;准确获取这些信息可以帮助他们优化软件性能、诊断问题并做出相应的调整。在Windows平台上实现这一目标会涉及到调用Windows系统AP…

Apifox 学习笔记 - 前置操作之:动态更新请求体中的时间戳

Apifox 学习笔记 - 前置操作之&#xff1a;动态更新请求体中的时间戳 1. 在前置操作中添加一个&#xff1a;自定义脚本或公共脚本2. 定义我们所需的环境变量。3. 在请求参数中使用【时间戳】4. 检验参考资料 1. 在前置操作中添加一个&#xff1a;自定义脚本或公共脚本 2. 定义我…

WPF DataGrid详细列表手动显示与隐藏

设置显示序号与折叠显示样式 <DataTemplate x:Key"dtNum"><Button BorderBrush"Transparent" Style"{x:Null}" Click"BtnRowDetail_ShowHideClick" FontSize"16" Background"Transparent"><Stack…

Dubbo从0到1——万字完整学习笔记

目录 RPC理论概述 RPC的基本思想 RPC的实现组成部分 RPC的实现流程 RPC的核心思想 RPC调用分类 初识Dubbo Dubbo特性 Dubbo设计架构 zookeeper环境搭建 搭建注册中心环境 搭建监控中心环境 Dubbo入门案例(Dubbo Spring) 实现步骤 搭建中介者组件共享资源 打包为jar&#xf…

京东数据接口:京东数据分析怎么做?

电商运营中数据分析的重要性不言而喻&#xff0c;而想要做数据分析&#xff0c;就要先找到数据&#xff0c;利用数据接口我们能够更轻松的获得比较全面的数据。因此&#xff0c;目前不少品牌商家都选择使用一些数据接口来获取相关电商数据、以更好地做好数据分析。 鲸参谋电商…

[0xGameCTF 2023] web题解

文章目录 [Week 1]signinbaby_phphello_httprepo_leakping [Week 2]ez_upload [Week 1] signin 打开题目&#xff0c;查看下js代码 在main.js里找到flag baby_php <?php // flag in flag.php highlight_file(__FILE__);if (isset($_GET[a]) && isset($_GET[b])…

2023年中国家纺行业研究报告

第一章 行业概况 1.1 定义 家纺行业&#xff0c;即家用纺织品行业&#xff0c;是纺织业中的一个重要分支&#xff0c;它与服装用纺织品和产业用纺织品共同构成了纺织业的三大支柱。家纺不仅仅是家庭生活中的必需品&#xff0c;更是居室装饰中不可或缺的元素&#xff0c;被誉为…

Java多线程篇(11)——BlockingQueue(优先级阻塞,延迟队列)

文章目录 1、PriorityBlockingQueue2、DelayQueue 1、PriorityBlockingQueue 优先级阻塞队列就是在优先级队列的基础上增加队列排序的功能&#xff0c;将高优先级排在前面&#xff0c;所以优先级队列的元素需要实现Comparator接口。 如果数据结构用数组去维护队列的话&#xf…

uniapp系列-图文并茂教你配置uniapp开发环境

环境安装 1. 安装 node.js (版本 18/16) 在搭建 Vue 开发环境之前&#xff0c;请先下载 node.js。 Node 可从官方网站下载&#xff0c;也可从中文网站下载。根据你的电脑选择 32 位 或 64 位。网站&#xff1a; Node 或者访问 历史版本 查看 node 版本 C:\Users> node -…

超级干货 | 数据平滑9大妙招(python版)

大家好&#xff0c;对数据进行平滑处理的方法有很多种&#xff0c;具体的选择取决于数据的性质和处理的目的。今天给大家分享9大常见数据平滑方法&#xff1a; 移动平均Moving Average 指数平滑Exponential Smoothing 低通滤波器 多项式拟合 贝塞尔曲线拟合 局部加权散点平…

【python海洋专题二十一】subplots共用一个colorbar

上期读取subplot&#xff0c;并出图 但是存在一些不完美&#xff0c;本期修饰 本期内容 共用colorbar 1&#xff1a;未共用colorbar 共用colorbar 1&#xff1a;横 2&#xff1a;纵 关键语句 图片 cb_ax fig.add_axes([0.15, 0.02, 0.6, 0.03]) #设置colarbar位置 cbar …

切换npm的版本

1、在配置环境变量的地址中&#xff0c;多准备几个已解压版本的node 2、要想升降版本直接更改该文件中的文件夹名称就行 环境变量中的path的值是不用变的C:\Program Files\nodejs

Leetcode 剑指 Offer II 048. 二叉树的序列化与反序列化

题目难度: 困难 原题链接 今天继续更新 Leetcode 的剑指 Offer&#xff08;专项突击版&#xff09;系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~ 题目描述 序列化是将一个数据结构或者对象转换为连续的比特位的操作&#…

商品分类代码

<!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>商品分类代码</title> <script type"text/javascript"> function MM_preloadImages() { //v3.0var ddocument; if(d.images){ if(!d.MM_p) d.MM_p…

5+甲基化+预后模型搭配实验

今天给同学们分享一篇甲基化预后模型实验的生信文章“Six immune-related promising biomarkers may promote hepatocellular carcinoma prognosis: a bioinformatics analysis and experimental validation”&#xff0c;这篇文章于2023年3月23日发表在Cancer Cell Int期刊上&…

三极管和MOS如何导通

三极管类型 原理图分析三极管&#xff0c;先看看它是什么类型&#xff0c;是PNP还是NPN。 一般通过看E极&#xff08;发射极&#xff09;流向&#xff0c;从B&#xff08;基极&#xff09;到E&#xff08;发射极&#xff09;为NPN。从E&#xff08;发射极&#xff09;到B&…

新的U-Net 网络结构

最近看到一篇很有趣的文章&#xff0c;Rethinking the unpretentious U-net for medical ultrasound image segmentation 这个文章提出了一种新的U-Net 网络结构。以前大家使用U-Net 喜欢加入新的模块或者使用多个U-Net 并联的方法进行语义分割。这篇文章提出了一种的新U-Net 结…

人工智能聊天机器人如何满足企业和客户不断变化的需求?

随着数字化转型的加速&#xff0c;企业与客户之间的沟通方式也在发生变化。传统的电话和电子邮件已经无法满足客户的即时需求和个性化体验。而人工智能聊天机器人作为一种智能助手&#xff0c;通过其快速、便捷和智能的特点&#xff0c;正在成为企业与客户之间沟通的新方式。 |…