Linux产生死锁的必要条件和常见的锁种类

这篇具有很好参考价值的文章主要介绍了Linux产生死锁的必要条件和常见的锁种类。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

  1. 之前面试的时候,有面试官问我产生死锁的(4个)必要条件,这个我之前有了解过,但是当时觉得这些必要条件很官方,也就没有重视,最后答得支支吾吾,面试官笑着说下去去可以看看,这个在面试中跟智能指针一样还挺常见的;(面试全程都很顺利,卡在这个简单的问题上确实不应该)
  2. 由此面试碰到了让我介绍linux下mutex的种类,这个也是之前略知一二,但是详细场景和机制还是欠缺;

这篇博客根据上面两个面试中出现的问题,以本人个人理解进行总结:


产生死锁的4个必要条件

下面四个必要条件不详细介绍,如果不理解需要温习一下mutex互斥量的作用和lock,unlock加锁解锁的底层原理;

(1)互斥条件:进程要求对所分配的资源进行排它性控制,即所分配的资源在一段时间内某资源仅为一进程所占用
(2)请求与保持条件:当进程因请求资源而阻塞时,对已获得的资源保持不放。(请求新资源的时候,保持已获得的旧资源)
(3)不剥夺条件进程已获得的资源在未使用完之前,不能剥夺,只能在使用完时由自己释放。
(4)循环等待条件:在发生死锁时,必然存在一个进程–资源的环形链


预防(解决)死锁

破坏4个必要条件中的任一个:

互斥这个规则,这个为了临界区的安全,肯定不能破坏呀;那就破坏后3个;

(1)资源一次性分配一次性分配所有资源,用完一次性全部释放,这样就不会再有别的进程请求时的冲突的现象了:

(2)可剥夺资源:即当某进程获得了部分资源,但得不到其它资源,则释放(剥夺)已占有的资源(破坏不可剥夺条件)
(3)资源有序分配法:系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反,就不会出现环路了(破坏环路等待条件);


Linux常见的锁

我们在开发中常用的锁主要有互斥锁,递归锁,自旋锁,读写锁、乐观锁和悲观锁这五种:

互斥锁(普通锁)

  • 正常进程间保护临界区的普通锁,没有什么特点,就是lock()和unlock()的正常上锁解锁;
  1. 当线程加锁失败时,内核会把线程的状态从运行状态设置为睡眠状态,然后把CPU切换给其他进程运行;

  2. 当需要的锁被其他线程释放时,之前睡眠状态的进程会变为就绪状态,然后内核会在合适的时候,把CPU切换给该线程运行。

普通锁看似使用简单,但是由于内核帮我们切换进程的内核态和用户态,存在一定的开销(进行了两次线程上下文切换)


自旋锁

  • 自旋锁在用户态完成加锁和解锁的操作不会主动产生内核态和用户态的切换和上下文的切换,所以相比互斥锁来说,会快一些,开销也小一些。

自旋锁的工作原理是在一段时间内反复尝试获取被占用的锁

加锁失败时,互斥锁用线程切换来应对,自旋锁则用忙等待(反复尝试获取锁)来应对


互斥锁和自旋锁小结

如果能确定被锁住的代码执行时间很短,而且多核处理器,就应该使用自旋锁减少了普通mutex线程上下文切换的开销;

如果被锁住的代码执行时间长,而且单核处理器,还是用普通mutex好点,因为这时候递归锁反复长时间轮询检测,无疑是浪费了cpu资源的举措

mutex和自旋锁是锁的两种最基本处理方式,更高级的锁都会选择其中一个方式来实现;

比如读写锁既可以选择基于互斥锁实现,也可以选择基于自旋锁实现。


递归锁

递归锁只是互斥锁的一个特例,同样只能有一个线程访问该对象;

递归锁允许同一个线程在 未释放其拥有的锁时 反复对 该锁 进行加锁操作(普通的锁就死锁了)

显然递归锁的常见场景就是对某一个包含加锁操作的递归类型函数进行调用; 某线程反复递归这个函数的时候,使用递归锁就不会像普通mutex那样第二次遇到加锁操作就直接进入睡眠状态挂起了;


读写锁

线程间读临界区资源的时候,不阻塞只有在有写的时候才起到mutex的作用,线程间互相阻塞;

这是一种提高效率的锁,比如mysql中的读写锁,读的时候因为不会修改临界区的资源,不会产生线程安全问题,因此读不阻塞效率更高;

写的时候存在线程安全问题,那就阻塞了;


乐观锁与悲观锁

悲观锁

前面提到的互斥锁、自旋锁、读写锁,都属于悲观锁

悲观锁认为多线程同时对共享资源进行修改的事件发生概率比较高,很容易出现冲突问题,所以访问共享资源前,必须先上锁。(做法有点谨慎,悲观,因此得名)


乐观锁(无锁编程)

  • 与悲观锁相反,乐观锁认为冲突的概率很低;

它的工作方式是:先修改完共享资源,再验证这段时间内有没有发生冲突

  1. 如果没有其他线程在修改资源,那么操作完成;(赚了,没发生冲突而且执行效率还高)
  2. 如果发现有其他线程已经修改过这个资源,就直接无脑放弃本次操作。(不亏,有冲突,放弃这次操作以免事态恶化,之后进行重试; 做法很乐观,因此得名)

乐观锁全程没有加锁,所以它也叫无锁编程


乐观锁和悲观锁小结

悲观锁直接进行加锁操作,进行加锁的操作,适用于冲突事件发生概率高的场景(这个场景用悲观锁得不停地)

乐观锁虽然去除了加锁解锁的操作,但是一旦发生冲突,重试的成本其实也非常高,所以只有在冲突事件发生的概率非常低,且加锁成本非常高的场景(比如cpu执行效率非常快)时,才考虑使用乐观锁

其他锁(了解)

还有很多锁,比如mysql在RR隔离级别下处理幻读问题使用了row行锁+GAP间隙锁等,都是一些高级的适用于某种场景的锁,所以锁的可拓展性还是很大的;文章来源地址https://www.toymoban.com/news/detail-833180.html

到了这里,关于Linux产生死锁的必要条件和常见的锁种类的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【100个 Unity实用技能】☀️ | 关于触发器互相检测的必要前提条件配置

    老规矩,先介绍一下 Unity 的科普小知识: Unity 是 实时3D互动内容创作和运营平台 。 包括 游戏开发 、 美术 、 建筑 、 汽车设计 、 影视 在内的所有创作者,借助 Unity 将创意变成现实。 Unity 平台提供一整套完善的软件解决方案,可用于创作、运营和变现任何实时互动的2D和

    2023年04月09日
    浏览(77)
  • 越细粒度的锁越好吗?产生死锁怎么办?

    大家好,我是哪吒。 上一篇提到了锁粒度的问题,使用“越细粒度的锁越好”,真的是这样吗?会不会产生一些其它问题?

    2024年02月08日
    浏览(42)
  • Java进阶(6)——抢购问题中的数据不安全(非原子性问题)& Java中的synchronize和ReentrantLock锁使用 & 死锁及其产生的条件

    1.大量请求拥挤抢购中的数据不安全问题; 2.事务ACID:原子性(Atomicity)一致性(Consistency)隔离性(Isolation)持久性(Durability); 3.线程安全特征:原子性(Atomicity)可见性(Visibility)有序性(Ordering); 4.java中的锁初步,synchronize锁和ReentrantLock锁使用初步; 5.滥用锁的问

    2024年02月11日
    浏览(40)
  • MySQL innoDB 间隙锁产生的死锁问题

    线上经常偶发死锁问题,当时处理一张表,也没有联表处理,但是有两个mq入口,并且消息体存在一样的情况,频率还不是很低,这么一个背景,我非常容易怀疑到,两个消息同时近到这一个事务里面导致的,但是是偶发的,又模拟不出来什么场景会导致死锁,只能进行代码

    2024年02月08日
    浏览(39)
  • 什么条件下会出现死锁,如何避免?

    死锁,简单来说就是两个或者两个以上的线程在执行过程中,去争夺同一个共享资源导致相互等待的现象。如果没有外部干预,线程会一直处于阻塞状态,无法往下执行。这样一直等待处于阻塞状态的线程,被称为死锁线程。 产生死锁需要同时满足以下四个条件: 第一个:

    2024年02月12日
    浏览(55)
  • 多线程常见的锁策略

    目录 1.1 乐观锁 和 悲观锁 1.2 轻量级锁 和 重量级锁 1.3 自旋锁 和 挂起等待锁 1.4 互斥锁 和 读写锁 1.5 可重入锁 和 不可重入锁 1.6 公平锁 和 非公平锁 1.7 synchronized 锁的属性 说到锁,Java 里面常用的锁有 synchronized ,锁的意义在于在多线程并发执行的时候保证线程安全,防止

    2023年04月25日
    浏览(73)
  • 设计模式第九讲:常见重构技巧 - 去除不必要的!=

    项目中会存在大量判空代码,多么丑陋繁冗!如何避免这种情况?我们是否滥用了判空呢?本文是设计模式第九讲,讲解常见重构技巧:去除不必要的!= 通常是这样的 初步的,使用Apache Commons,Guvava,Hutool等 StringUtils 考虑用Assert断言 逐级判断空,还是抛出自定义异常,还是

    2024年02月11日
    浏览(43)
  • 【Linux】修复 Linux 错误 - 没有可用的锁

    在使用 Linux 操作系统时,有时会遇到错误消息“没有可用的锁”。这个错误通常与文件或进程锁相关,可能会导致系统功能受限或无法正常工作。本文将介绍该错误的原因和解决方法。 “没有可用的锁”错误通常是由以下几个原因引起的: 文件锁冲突:当多个进程同时尝试

    2024年02月03日
    浏览(33)
  • Java避免死锁的几个常见方法(有测试代码和分析过程)

    目录 Java避免死锁的几个常见方法 死锁产生的条件 上死锁代码 然后 :jstack 14320 jstack.text Java避免死锁的几个常见方法 Java避免死锁的几个常见方法 避免一个线程同时获取多个锁。 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。 尝试使用定时锁,使

    2023年04月16日
    浏览(77)
  • 【Linux】线程安全-死锁

    死锁的两种场景: 线程加锁之后一直没有将锁释放,在上一篇文中,我们模拟过这种场景,某个线程拿到锁,进行加锁,线程退出之前没有释放锁,导致后面的线程不能拿到锁,一直在等待加锁,导致程序一直不退出,这也是为什么条件变量等待函数中第二个参数是锁的原因

    2024年02月10日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包