【操作系统】死锁

【操作系统】线程同步、线程互斥、原子操作 一问中,使用到了 这个东西,当一个线程进入临界区后把门锁起来,其他线程跑到这里来发现锁被使用了,就等着锁被释放。
当然,这是理想的情况下,但实际开发中还会出现下面的情况。

死锁栗子

mutex;   //代表一个全局互斥对象

void  A() {
    mutex.lock();

    //这里操作共享数据

    B();
    mutex.unlock();
    return;
}

void  B()
{
    mutex.lock();

    //这里操作共享数据

    mutex.unlock();
    return;
}

可别想的是自己写不出这样的代码来,哈哈哈。

死锁概念

死锁是指在一组进程中的各个线程均占有不会释放的资源,但因互相申请被其他进程所站用不会释放的 资源而处于的一种永久等待状态。

产生死锁的 4 个必要条件

1、互斥条件:一个资源每次只能被一个执行流使用。
2、请求与保持条件:一个执行流因请求资源而阻塞时,对已获得的资源保持不放。
3、不剥夺条件:一个执行流已获得的资源,在末使用完之前,不能强行剥夺。
4、循环等待条件:若干执行流之间形成一种头尾相接的循环等待资源的关系。

常见场景

1、一个线程加锁后再次尝试加锁。
2、两个线程 t1, t2 有两把锁 m1, m2,线程 t1 先去获取锁 m1 再去获取锁 m2,线程 t2 先去获取锁 m2 再去获取锁 m1,造成死锁。
3、多个线程多个锁。哲学家就餐问题!

哲学家就餐问题

哲学家就餐问题: 比如5个哲学家和五根筷子。

哲学家行为:1. 思考(啥都不干) 2. 吃鸡

极端情况,五个哲学家同时拿起自己左手边的筷子,然后哲学家就无法再拿起右手的筷子。
那么当所有哲学家都不愿意放下左手的筷子,就会造成所有线程死锁。

解决方法:
方法1
做出约定:先给每个筷子编号,约定哲学家每次先拿编号小的筷子。若所有哲学家依次拿筷子,到最后的哲学家肯定就会拿另一根筷子,就可以避免出现死锁。这样的顺序约定是破除死锁的常见办法。破除死锁中的"环路等待"条件。
比如现在我给每个筷子给上编号,当一号哲学家拿的时候先拿1号筷子,二号哲学家先拿2号筷子。。以此类推当五号哲学家拿筷子的时候,不会再去拿5号筷子了,而是尝试去拿1号筷子,但是1号筷子已经被一号哲学家拿过了,所以五号哲学家就需要等待。四号哲学家就可以再拿5号筷子可以吃饭了,等他吃完释放4 5 号筷子,3号哲学家就可以吃饭了。。以此类推。这样就解决了。

方法2
信号量 PV 操作。
搞一个信号量初始化为 4(比锁数量少 1)
每个哲学家拿筷子的时候进行 P 操作,当第 5 个人在申请锁的时候信号量为 0 就不可以申请了。

如何避免死锁

1、破坏死锁的 4 个条件。
2、加锁顺序一致。
3、避免锁未释放。
4、资源一次性分配。
5、算法(死锁检测算法、银行家算法)。


参考文章:
https://blog.csdn.net/weixin_42678507/article/details/90906296

更多:
C++ 死锁案例:
https://blog.csdn.net/i_likechard/article/details/78206018

EOF

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章