我是靠谱客的博主 感动手套,最近开发中收集的这篇文章主要介绍Linux死锁检测,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

死锁概念:

死锁是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待的现象. 例如: A线程占有1号锁,B线程占有2号锁, 当A想进一步获取2号锁, B想获取1号锁. A.B线程都进入等待对方释放锁的等待中, 造成了死锁.

死锁出现原因:

(1) 因为系统资源不足。

(2) 进程运行推进的顺序不合适。

(3) 资源分配不当等。

出现死锁的时候征兆

业务无法正常处理, 业务日志输出不完整.

如何检测程序中是否存在死锁呢? 如果我们能在加锁的时候把线程id和互斥锁做一个绑定, 在解锁的时候做一个解绑定, 用一个线程去实时检测是否出现两个线程绑定到对方已占有的互斥锁, 如果出现,就说明出现了死锁.

初始化hook函数

 dlsym 参考动态库装载及 dlsym的RTLD_NEXT参数详解_焱齿的博客-CSDN博客_rtld_next 头文件

我们在代码里实现了自己的pthread_mutex_lock和pthread_mutex_unlock,在代码里调用的话,就会调用我们自己写的函数

 死锁的发生, 必然意味着有向图(依赖关系)的构建存在环.

关于检测模型, 我们可以这么假定, 锁为有向边, 申请锁的线程A为起点, 拥有锁的线程B为终点. 这样就形成线程A到线程B的一条有向边. 而众多的锁(边)和线程(点), 就构成了一个有向图.

于是死锁检测 就转变为图论中有向图的环判断问题.

#define _GNU_SOURCE
#include <dlfcn.h>

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

#include <stdlib.h>
#include <stdint.h>

#include <unistd.h>

#define THREAD_NUM      10

typedef unsigned long int uint64;

/* 
	gcc -o deadlock deadlock_success.c -lpthread -ldl 
*/

//声明函数指针
typedef int (*pthread_mutex_lock_t)(pthread_mutex_t *mutex);

pthread_mutex_lock_t pthread_mutex_lock_f;

//声明函数指针
typedef int (*pthread_mutex_unlock_t)(pthread_mutex_t *mutex);

pthread_mutex_unlock_t pthread_mutex_unlock_f;


#if 1 // graph

#define MAX		100

enum Type {PROCESS, RESOURCE};

struct source_type 
{
	//线程id
	uint64 id;        
	enum Type type;

	//锁id
	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;
		} 
		printf("s.id:%ld,j.id;%ldn", v->s.id,j.id);	
		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("deadlock : ");
	for (i = 0; i < k-1; i++) 
	{
		printf("%ld --> ", tg->list[path[i]].s.id);

	}

	printf("%ldn", 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

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

}


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

}


#if 1

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;

}

#endif

int inc(int *value, int add) 
{
	int old;
	__asm__ volatile(
		"lock;xaddl %2, %1;"
		: "=a"(old)
		: "m"(*value), "a" (add)
		: "cc", "memory"
	);
	
	return old;
}


void print_locklist(void) 
{
	int i = 0;
	printf("print_locklist: n");
	printf("---------------------n");
	for (i = 0;i < tg->lockidx;i ++) 
	{
		printf("threadid : %ld, lockid: %ldn", tg->locklist[i].id, tg->locklist[i].lock_id);
	}
	printf("---------------------nnn");
}

void lock_before(uint64 thread_id, uint64 lockaddr) 
{
	int idx = 0;
	// list<threadid, toThreadid>
	printf("lock_before 1 : %ld mutex_1: %ld ,tg->lockidx:%ldn", thread_id, lockaddr, tg->lockidx);
	for(idx = 0; idx < tg->lockidx; idx++) 
	{
		if ((tg->locklist[idx].lock_id == lockaddr)) 
		{
			struct source_type from;
			from.id = thread_id;
			from.type = PROCESS;
			add_vertex(from);

			struct source_type to;
			to.id = tg->locklist[idx].id;    
			tg->locklist[idx].degress++;
			printf("lock_before_ form.id:%ld,to.id:%ld,tg->locklist[idx].degress=%d,mutex:%ldn",thread_id,to.id,tg->locklist[idx].degress,lockaddr);
			to.type = PROCESS;
			add_vertex(to);
			
			if (!verify_edge(from, to)) 
			{
				add_edge(from, to); // 
			}

		}
	}
}

void lock_after(uint64 thread_id, uint64 lockaddr) 
{
	printf("lock_after 1 : %ld mutex_1: %ld ,tg->lockidx:%ldn", thread_id, lockaddr, tg->lockidx);
	int idx = 0;
	if (-1 == (idx = search_lock(lockaddr))) //锁没有被别人占用
	{  // lock list opera 

		int eidx = search_empty_lock(lockaddr);
		
		tg->locklist[eidx].id = thread_id;
		tg->locklist[eidx].lock_id = lockaddr;
		
		inc(&tg->lockidx, 1); //lock_after之后,lockidx执行+1操作

		printf("lock_after 2 : %ld mutex_1: %ld ,tg->lockidx:%ldn", thread_id, lockaddr, tg->lockidx);
		
	} 
	else 
	{
		struct source_type from;
		from.id = thread_id;
		from.type = PROCESS;

		struct source_type to;
		to.id = tg->locklist[idx].id;
		tg->locklist[idx].degress --;
		printf("lock_after_form.id:%ld,to.id:%ld,tg->locklist[idx].degress=%d,mutex:%ldn",thread_id,to.id,tg->locklist[idx].degress,lockaddr);
		to.type = PROCESS;

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

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

void unlock_after(uint64 thread_id, uint64 lockaddr) 
{
	int idx = search_lock(lockaddr);
	printf("unlock_after 2 : %ld mutex_1: %ld ,tg->lockidx:%ld,degress=%dn", thread_id, lockaddr, tg->lockidx,tg->locklist[idx].degress);
	if (tg->locklist[idx].degress == 0) 
	{
		tg->locklist[idx].id = 0;
		tg->locklist[idx].lock_id = 0;
		inc(&tg->lockidx, -1);
	}
	
}


int pthread_mutex_lock(pthread_mutex_t *mutex) 
{
    pthread_t selfid = pthread_self(); //
    
	lock_before(selfid, (uint64)mutex);
    pthread_mutex_lock_f(mutex);
	lock_after(selfid, (uint64)mutex);

}

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

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


}

static int init_hook() 
{
    pthread_mutex_lock_f = dlsym(RTLD_NEXT, "pthread_mutex_lock");

    pthread_mutex_unlock_f = dlsym(RTLD_NEXT, "pthread_mutex_unlock");
}

//demo测试

最后

以上就是感动手套为你收集整理的Linux死锁检测的全部内容,希望文章能够帮你解决Linux死锁检测所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(48)

评论列表共有 0 条评论

立即
投稿
返回
顶部