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;%ld\n", 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("%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

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

}


#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: %ld\n", tg->locklist[i].id, tg->locklist[i].lock_id);
	}
	printf("---------------------\n\n\n");
}

void lock_before(uint64 thread_id, uint64 lockaddr) 
{
	int idx = 0;
	// list<threadid, toThreadid>
	printf("lock_before 1 : %ld mutex_1: %ld ,tg->lockidx:%ld\n", 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:%ld\n",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:%ld\n", 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:%ld\n", 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:%ld\n",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=%d\n", 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测试

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值