我是靠谱客的博主 仁爱彩虹,这篇文章主要介绍死锁检测组件-设想死锁检测组件-设想死锁的构建pthread的hook图的构建,现在分享给大家,希望可以做个参考。

死锁检测组件-设想

现在有三个临界资源和三把锁绑定了,三把锁又分别被三个线程占用。(不用关注临界资源,因为锁和临界资源是绑定的)

20230217203523

但现在出现这种情况:线程1去申请获取锁2,线程2申请获取锁3,线程3申请获取锁1,这样就会造成死锁:

20230215224714

死锁问题,可转换为有向图的环路检测

死锁的构建

有四个线程,4把锁,以下代码一定会产生死锁

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
pthread_mutex_t mtx1 = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t mtx2 = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t mtx3 = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t mtx4 = PTHREAD_MUTEX_INITIALIZER; void *thread_routine_a(void *arg) { printf("thread_routine a n"); pthread_mutex_lock(&mtx1); sleep(1); pthread_mutex_lock(&mtx2); pthread_mutex_unlock(&mtx2); pthread_mutex_unlock(&mtx1); printf("thread_routine a exitn"); } void *thread_routine_b(void *arg) { printf("thread_routine b n"); pthread_mutex_lock(&mtx2); sleep(1); pthread_mutex_lock(&mtx3); pthread_mutex_unlock(&mtx3); pthread_mutex_unlock(&mtx2); printf("thread_routine b exit n"); // ----- pthread_mutex_lock(&mtx1); } void *thread_routine_c(void *arg) { printf("thread_routine c n"); pthread_mutex_lock(&mtx3); sleep(1); pthread_mutex_lock(&mtx4); pthread_mutex_unlock(&mtx4); pthread_mutex_unlock(&mtx3); printf("thread_routine c exit n"); } void *thread_routine_d(void *arg) { printf("thread_routine d n"); pthread_mutex_lock(&mtx4); sleep(1); pthread_mutex_lock(&mtx1); pthread_mutex_unlock(&mtx1); pthread_mutex_unlock(&mtx4); printf("thread_routine d exit n"); } int main() { #if 1 init_hook(); pthread_t tid1, tid2, tid3, tid4; pthread_create(&tid1, NULL, thread_routine_a, NULL); pthread_create(&tid2, NULL, thread_routine_b, NULL); pthread_create(&tid3, NULL, thread_routine_c, NULL); pthread_create(&tid4, NULL, thread_routine_d, NULL); pthread_join(tid1, NULL); pthread_join(tid2, NULL); pthread_join(tid3, NULL); pthread_join(tid4, NULL); }

这里产生了:线程a => 线程b => 线程c => 线程d =》 线程a的这样一个环路

但是我们不知道哪把锁被哪个线程占用了,没法构建有向图,也就无法得知是否产生了这样一个环路

这时,可以用hook,调自己写的 pthread_mutex_lock,将线程和锁的映射关系保存起来

pthread的hook

有点像装饰器模式

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 函数指针 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; static int init_hook() { // RTLD_NEXT可以理解为代码段,在这里面找pthread_mutex_lock函数名,把地址返回 // 所以pthread_mutex_lock_f就是静态或动态库里的pthread_mutex_lock锁函数 pthread_mutex_lock_f = dlsym(RTLD_NEXT, "pthread_mutex_lock"); pthread_mutex_unlock_f = dlsym(RTLD_NEXT, "pthread_mutex_unlock"); } int pthread_mutex_lock(pthread_mutex_t *mutex) { printf("pthread_mutex_lock selfid %ld, mutex: %pn", pthread_self(), mutex); beforelock(pthread_self(), mutex); pthread_mutex_lock_f(mutex); // 用钩子的好处,给系统函数命一个别名 afterlock(pthread_self(), mutex); } int pthread_mutex_unlock(pthread_mutex_t *mutex) { printf("pthread_mutex_unlockn"); pthread_mutex_unlock_f(mutex); afterunlock(pthread_self(), mutex); }

这样,在加锁的时候,就能知道锁id(mutex)和线程id的对应关系

图的构建

通过邻接表实现有向图,如:线程1等待线程2释放锁,则将线程id2挂到线程1后面

20230216225923

而如何知道线程1申请的锁被线程2占用了呢:设置一个 mutex 和 thread的映射列表(结构体数组),通过mutex返回threadid。

如线程1对mutex1加锁,将(mutex1,threadid1)加入locklist中,表示mutex1被线程1占用了

图的邻接表生成:当前线程根据要申请的mutex a找到占用这把锁的线程id A(通过映射列表),将改线程追加到自己的后面

通过邻接表检测环路:DFS,检测过的标为1,再遇到一个1就表示死锁了

20230216230719

那我们怎么把这个图构建起来: 通过三个原语操作
beforelock、afterlock、afterrunlock 以后要用到再说吧

至此,死锁检测组件设计的大致思路为:通过hook保存muitex和threadid的映射关系,根据这个映射关系生成线程之间的有向图(邻接表),再利用dfs检测图的环路

最后

以上就是仁爱彩虹最近收集整理的关于死锁检测组件-设想死锁检测组件-设想死锁的构建pthread的hook图的构建的全部内容,更多相关死锁检测组件-设想死锁检测组件-设想死锁内容请搜索靠谱客的其他文章。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部