1 死锁形成的条件
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
通过模拟不同的死锁场景得到的结果: