死锁监测

死锁现象:
CPU占用率100% ->while(1); 或 死锁;
死锁概念: 多个线程相互等待被占有的资源,陷入一种互相阻塞的情况,这就是死锁;

你有没有遇到死锁,如何检测排查了?
如何检测这种在死锁中的环,如果成环,那大概率死锁;(算法: 有向图是否成环

如果构建有向图?--> 如何通过资源找到对应线程; 如何知道线程想占用的资源?
1、 线程对应线程号; 锁的指针对应一个锁号; 通过关系表,可以查询到两者间的映射关系;表示了线程占用了哪些锁;
2、 如何表示线程想占用哪些锁呢?, 意味着还没lock; 这里就区分处线程下lock之前和lock之后,线程与锁的关系不同;形象的说,加锁前是想要获得的关系,加锁后是已经占用的关系;

hook协程三步骤: 我们使用hook对C的pthread_mutex进行重写,实现锁前逻辑和锁后逻辑
1、定义函数原型;

typedef ssize_t (*read_t)(int fd, void *buf, size_t count);
read_t read_f = NULL;

typedef ssize_t (*write_t)(int fd, const void *buf, size_t count);
write_t write_f = NULL;

2、Hook:拦截

ssize_t read(int fd, void *buf, size_t count) {}
ssize_t write(int fd, const void *buf, size_t count) {
    printf("write: %s\n", (const char *)buf);
    return write_f(fd, buf, count);
}

3、使用函数原型前必须初始化 Hook

void init_hook(void) {
    if (!read_f) {
        read_f = dlsym(RTLD_NEXT, "read");
    }

    if (!write_f) {
        write_f = dlsym(RTLD_NEXT, "write");
    }
}

设计的根本关系:
1
其中,我们依靠邻接表 存储有向图, 寻找是否有环;
用锁和线程的关系表 帮助索引锁和对应线程;

在lock前,进行锁前处理,若锁已经被其他线程持有,则添加等待边;
在加锁后,如果当前线程能顺利加完锁,证明该线程应该独占此锁,在关系表中,双向绑定这层关系,并将尝试等待的关系边删除;如果锁未在locklist记录,则创建新记录,持有者为tid;如果有记录,则释放之前的邻接边,并更新锁的线程为当前线程。

在解锁时,类似于futex底层,每个锁的引用计数不为0,则还有线程在等待该锁,那锁不清除。

当前的设计中,每个线程可以同时拥有多把锁,也只能等待一把锁;如当 t1 成功获得 r1 和 r2 后,它在 locklist 中会有两条记录:

| lock_id | 持有者线程 |
| ------- | ----- |
| &r1     | t1    |
| &r2     | t1    |

关键伪代码:

before_lock(pthread tid, uint64_t mutex){
  //锁被持有了,在conn_list找到,对当前线程加边,表示等待 
  int idx = 0;
  if((idx = seach_mutex(mutex)) != -1){

      tid2 = conn_list[idx].tid;
      add_edge(tid, tid2)  //链表
  }
}

after_lock(pthread tid, uint64_t mutex){
  //锁之前被持有了,在conn_list修改关系表,删除当前等待边
  //如果没有被持有,说明是新锁,添加进关系表
  int idx = 0;
  if((idx = seach_mutex(mutex)) != -1){

      tid2 = conn_list[idx].tid;

      remove_edge(tid, tid2)  //链表
      conn_list[idx].tid = tid;
  }else{//conn_list数组,由于锁本身可以被回收,可能出现空缺,而我们不想移动数组,那就把回收的锁,初始化,后续找这些空位,填充,找不到就是末尾
    int idx1 = search_elock();
    conn_list[idx1].tid = tid;
    conn_list[idx1].lid = mutex;
}


unlock(pthread tid, uint64_t mutex){
    //如果没有其他线程等待该所,conn_list数组下消除该关系;置空;
    int idx = seach_mutex(mutex);
    if( conn_list[idx1].wait_num == 0){
      conn_list[idx1].tid = 0;
      conn_list[idx1].lid = 0;
    }
}
posted @ 2026-08-07 16:16  超级麋鹿  阅读(8)  评论(0)    收藏  举报