C++后端开发(3.2.4)——手写死锁检测组件
小节提纲
死锁现象以及原理
pthread_mutex_lock/pthread_mutex_unlock disym的实现
有向图的构建
有向图dfs判断环的存在
三个原语操作lock_before,lock_after,unlock_after
死锁检程线程的实现
1 死锁现象以及原理
1.1 死锁概念及产生原理
概念: 多个并发进程因争夺系统资源而产生相互等待的现象。
原理: 当一组进程中的每个进程都在等待某个事件发生,而只有这组进程中的其他进程才能触发该事件,这就称这组进程发生了死锁。
本质原因:
- 系统资源有限。
- 进程推进顺序不合理。
1.2 死锁产生的4个必要条件
- 互斥: 某种资源一次只允许一个进程访问,即该资源一旦分配给某个进程,其他进程就不能再访问,直到该进程访问结束。
- 占有且等待: 一个进程本身占有资源(一种或多种),同时还有资源未得到满足,正在等待其他进程释放该资源。
- 不可抢占: 别人已经占有了某项资源,你不能因为自己也需要该资源,就去把别人的资源抢过来。
- 循环等待: 存在一个进程链,使得每个进程都占有下一个进程所需的至少一种资源。
当以上四个条件均满足,必然会造成死锁,发生死锁的进程无法进行下去,它们所持有的资源也无法释放。这样会导致CPU的吞吐量下降。所以死锁情况是会浪费系统资源和影响计算机的使用性能的。那么,解决死锁问题就是相当有必要的了。
1.3 死锁举例
死锁,是指多个线程或者进程在运行过程中因争夺资源而造成的一种僵局,当进程或者线程处于这种僵持状态,若无外力作用,它们将无法再向前推进。如下图所示,线程 A 想获取线程 B 的锁,线程 B 想获取线程 C 的锁,线程 C 想获取线程 D 的锁, 线程 D 想获取线程 A 的。
锁,从而构建了一个资源获取环。
2 死锁检测实现
资源获取环可以采用图来存储, 使用有向图来存储。 线程 A 获取线程 B 已占用的锁,则为线程 A 指向线程 B。 如何为线程 B 已占用的锁?运行过程线程 B 获取成功的锁。
检测的原理采用另一个线程定时对图进程检测是否有环的存在。
2.1 有向图的构建
2.1.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;
2.1.2 图算法,检测成环
// 创造顶点
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