死锁检测组件-学习(一)

一、死锁

1、什么是死锁?

两个或两个以上的线程或进程,因争夺资源而造成的一种互相等待的现象。

在这里插入图片描述

2、死锁检测的方法:

    1. 代码审查法:通过分析代码定位死锁位置,该方法对开发人员的代码理解能力要求较高。
    1. 有向图检测法:基于资源分配和请求情况构建有向图,检测图中是否存在环路来判定死锁。
    1. 资源分配图法:一种利用资源分配关系的有向图分析方法。图中包含两类节点(资源节点与进程节点)和两类有向边(分配边与请求边)。
    1. 银行家算法:通过模拟资源分配过程,提前预测系统是否可能进入不安全状态。

二、具体实现

1、死锁的构建:

定义三个线程,三个互斥锁

pthread_t t1, t2, t3;
    
pthread_create(&t1, NULL, Funct1, NULL);
pthread_create(&t2, NULL, Funct2, NULL);
pthread_create(&t3, NULL, Funct3, NULL);

pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
/*....*/
void *Funct1(void *arg)
{
    printf("thread1: %ld\n", pthread_self());

    pthread_mutex_lock(&r1);
    sleep(2);
    pthread_mutex_lock(&r2);

    pthread_mutex_unlock(&r2);
    pthread_mutex_unlock(&r1);
}
void *Funct2(void *arg){
    /*...*/
}
void *Funct3(void *arg){
    /*...*/
}

在这里插入图片描述

在这里插入图片描述

2、建立有向图

采用邻接链表法建立有向图
在这里插入图片描述

/*用于表示图中的节点类型。它有两个值:PROCESS 和 RESOURCE,
*分别表示节点可以是一个进程或一个资源。
*/
enum Type {PROCESS, RESOURCE};

typedef struct source_type{
    uint64 id;
    enum Type type;

    uint64 lock_id;
    int degress;
}source_type;

typedef struct vertex{
    source_type s;
    vertex *next;
}vertex;

typedef struct graph{
    vertex list[MAX_NUM];
    int num;

    source_type locklist[MAX_NUM];
    int lockidx;

    pthread_mutex_t _mutex;
}graph;

3、检测有向图是否成环

1、加锁之前先查表,看是否已占用

否,正常进行, 有向图中增加一条边
是,查找该线程id      self ---------> tid
/**
 * @brief 在加锁前记录锁的信息
 *
 * 在尝试获取锁之前,记录锁的信息和与之相关联的进程信息,包括进程ID和锁ID,以及锁的度数(即获取该锁的进程数量)。
 * 如果当前进程和锁相关联的进程之间尚未建立边,则添加边。
 *
 * @param tid 进程ID
 * @param lockaddr 锁的地址
 */
void lock_before(uint64 tid, uint64 lockaddr)
{
    int idx = 0;

    for (idx = 0; 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);
        }
    }
}

2、加锁之后,更新表中的关系

/**
 * @brief 在给定线程ID和锁地址后锁定该锁
 *
 * 如果锁地址对应的锁不存在,则在锁列表中创建一个新的锁,并将其与给定线程ID关联。
 * 如果锁地址对应的锁已经存在,则将给定线程ID与该锁关联,并更新相关数据结构。
 *
 * @param tid 线程ID
 * @param lockaddr 锁地址
 */
void lock_after(uint64 tid, uint64 lockaddr)
{

    int idx = 0;
    if (-1 == (idx = search_lock(lockaddr)))
    { //

        int eidx = search_empty_lock(lockaddr);

        tg->locklist[eidx].id = tid;
        tg->locklist[eidx].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;
    }
}

3、加锁之后解锁,删除表中的该关系

/**
 * @brief 在指定的线程解锁后,更新锁列表中的信息
 *
 * 根据给定的线程ID和锁地址,在锁列表中搜索对应的锁,并更新其状态。
 * 如果该锁已经被完全解锁(即所有持有该锁的线程都已经解锁),则将该锁从锁列表中移除。
 *
 * @param tid 线程ID
 * @param lockaddr 锁地址
 */
void unlock_after(uint64 tid, uint64 lockaddr)
{

    int idx = search_lock(lockaddr);

    if (tg->locklist[idx].degress == 0)
    {
        tg->locklist[idx].id = 0;
        tg->locklist[idx].lock_id = 0;
    }
}

在这里插入图片描述

4、检测是否成环,主要是使用DFS算法

三、总结

  • 1、两个或两个以上的线程或进程,因争夺资源而造成的一种互相等待的现象,叫做死锁。
  • 2、可以通过资源分配和请求,可以构造有向图,然后通过检测有向图是否成环。
  • 3、代码过于冗长,本来是想封装成一个有向图文件,再调用,没想到出现各种传值问题,暂时只能放在一个文件里面,后面再重新整合下

四、问题

1、如何通过资源找到对应的线程

通过一张资源-线程表来确定。

2、如何知道线程想占用资源

加锁之前,记录线程的信息以及想要获取资源的信息;加锁之后,更新资源-线程表。

代码

Code

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值