自旋锁与互斥锁

  • 自旋锁与互斥锁
    • 理论分析
    • 互斥锁的问题
    • 自旋锁应用场景
    • 自旋锁实践
    • 总结

自旋锁与互斥锁

自旋锁和互斥锁是多线程程序中的重要概念。 它们被用来锁住一些共享资源, 以防止并发访问这些共享数据时可能导致的数据不一致问题。 但是它们的不同之处在哪里? 我们应该在什么时候用自旋锁代替互斥锁?

理论分析

从理论上说, 如果一个线程尝试加锁一个互斥锁的时候没有成功, 因为互斥锁已经被锁住了, 这个未获取锁的线程会休眠以使得其它线程可以马上运行。 这个线程会一直休眠, 直到持有锁的线程释放了互斥锁, 休眠的线程才会被唤醒。 如果一个线程尝试获得一个自旋锁的时候没有成功, 该线程会一直尝试加锁直到成功获取锁。 因此它不允许其它线程运行(当然, 操作系统会在该线程所在的时间片用完时, 强制切换到其它线程)。

互斥锁的问题

互斥锁存在的问题是, 线程的休眠和唤醒都是相当昂贵的操作, 它们需要大量的CPU指令, 因此需要花费一些时间。 如果互斥量仅仅被锁住很短的一段时间, 用来使线程休眠和唤醒线程的时间会比该线程睡眠的时间还长, 甚至有可能比不断在自旋锁上轮训的时间还长。自旋锁的问题是, 如果自旋锁被持有的时间过长, 其它尝试获取自旋锁的线程会一直轮训自旋锁的状态, 这将非常浪费CPU的执行时间, 这时候该线程睡眠会是一个更好的选择。

自旋锁应用场景

在单核/单CPU系统上使用自旋锁是没用的, 因为当线程尝试获取自旋锁不成功的时候会一直尝试, 这会一直占用CPU, 其它线程不可能运行, 因为其他线程不能运行, 这个锁也就不会被解锁。 换句话说, 在单核/单CPU的系统上,自旋锁除了浪费时间没有一点好处。 这时如果这个线程(记为A)可以休眠, 其它线程可以立即运行, 因为其它有可能解锁, 那么线程A可能在唤醒后继续执行。
在多核/多CPU的系统上, 特别是大量的线程只会短时间的持有锁的时候, 在使线程睡眠和唤醒线程上浪费大量的时间, 也许会显著降低程序的运行性能。 使用自旋锁, 线程可以充分利用调度程序分配的时间片(经常阻塞很短的时间, 不用休眠, 然后马上继续它们的工作了), 以达到更高的处理能力和吞吐量。

自旋锁实践

因为程序员往往并不能事先知道哪种方案会更好(比如, 不知道运行环境的CPU核的数量), 操作系统也不知道一段指令是不是针对单核或者多核环境下做过优化, 所以大部分操作系统并不严格区分互斥锁和自旋锁。 实际上, 绝大部分现代的操作系统采用的是混合型互斥锁(hybrid mutexes)和混合型自旋锁(hybrid spinlocks)。 它们是什么意思呢?
混合型互斥锁, 在多核系统上起初表现的像自旋锁一样, 如果一个线程不能获取互斥锁, 它不会马上被切换为休眠状态, 因为互斥量可能很快就被解锁, 所以这种机制会表现的像自旋锁一样。 只有在一段时间以后(或者尝试一定次数,或者其他指标)还不能获取锁, 它就会被切换为休眠状态。 如果运行在单核/单CPU上, 这种机制将不会自旋(就像上面解释的, 这种情况自旋没有什么好处)。
混合型自旋锁, 起初表现的和正常自旋锁一样, 但是为了避免浪费大量的CPU时间, 会有一个折中的策略。 这种机制不会把线程切换到休眠态(既然想要使用自旋锁, 那么你并不希望这种情况发生), 也许会决定放弃这个线程的执行(马上放弃或者等一段时间)并允许其他线程运行, 这样提高了自旋锁被解锁的可能性(大多数情况, 线程之间的切换操作比使线程休眠而后唤醒它要昂贵, 尽管那不是很明显)。

总结

如果对选择哪种方案感到疑惑, 那就使用互斥锁吧, 并且大多数现代的操作系统都允许在获取锁的时候自旋一段时间(混合型互斥锁)。 只有在一定条件下使用自旋锁才可以提高性能, 事实上, 你现在在做的项目可能没有一个能在通过自旋锁提高性能。 也许你考虑使用你自己定义的”锁对象”, 它可以在内部使用互斥锁或者自旋锁(例如: 在创建锁对象时, 用哪种机制是可配置的), 刚开始在所有的地方都是用互斥锁, 如果你认为在有些地方用自旋锁确实可以提高性能, 你可以试试, 并且比较两种情况的结果(使用一些性能评测工具), 但一定要在单核和多核环境上测试之后再下结论(如果你的代码是夸平台的, 也要尽可能在不同的平台上测试下)。

自旋锁替代互斥锁使用场景相关推荐

  1. 关抢占 自旋锁_互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景

    前言 生活中用到的锁,用途都比较简单粗暴,上锁基本是为了防止外人进来.电动车被偷等等. 但生活中也不是没有 BUG 的,比如加锁的电动车在「广西 - 窃·格瓦拉」面前,锁就是形同虚设,只要他愿意,他就 ...

  2. 自旋锁与互斥锁的使用场景分析

    本文不对自旋锁和互斥锁的概念做阐述,重点分析它们之间的区别和自旋锁的使用场景. 自旋锁和互斥锁的区别 a. 互斥锁加锁失败后,线程会释放 CPU,给其他线程:自旋锁加锁失败后,线程会忙等待,直到它拿到 ...

  3. 并发编程中常见的锁机制:乐观锁、悲观锁、CAS、自旋锁、互斥锁、读写锁

    文章目录 乐观锁 VS 悲观锁 悲观锁 乐观锁 CAS CAS机制 ABA问题 CAS的优缺点 互斥锁 VS 自旋锁 互斥锁 自旋锁 对比及应用场景 读写锁 实现方式 读写锁 VS 互斥锁 乐观锁 V ...

  4. 自旋锁、互斥锁和信号量

    自旋锁 Linux内核中最常见的锁是自旋锁(spin lock).自旋锁最多只能被一个可执行线程持有.如果一个执行线程试图获得一个已经被持有的自旋锁,那么该线程就会一直进行忙循环--旋转--等待锁重新 ...

  5. C# lock 语法糖实现原理--《.NET Core 底层入门》之自旋锁,互斥锁,混合锁,读写锁...

    在多线程环境中,多个线程可能会同时访问同一个资源,为了避免访问发生冲突,可以根据访问的复杂程度采取不同的措施 原子操作适用于简单的单个操作,无锁算法适用于相对简单的一连串操作,而线程锁适用于复杂的一连 ...

  6. 正确使用自旋锁、互斥锁

    最近在看alios-things的代码发现驱动程序中大量使用了自旋锁 . 如tty.c里面的函数实现都是通过自旋锁来实现对资源的访问保护. 看到这里首先会有疑问,自旋锁能保护临界区吗? 一般来说,自旋 ...

  7. c语言用户态锁使用,用户态自旋锁、读写自旋锁及互斥锁

    1.自旋锁 自旋锁最多可能被一个可执行线程所持有.一个被征用的自旋锁使得请求它的线程在等待锁重新可用时自旋(特别浪费处理器时间).所以自旋锁不应该被长时间持有. 自旋锁是不可递归的! (1)自旋锁相关 ...

  8. 分布式锁:互斥锁、自旋锁、读写锁、悲观锁、乐观锁

    前言 如何用好锁,也是程序员的基本素养之一了. 高并发的场景下,如果选对了合适的锁,则会大大提高系统的性能,否则性能会降低. 所以,知道各种锁的开销,以及应用场景是很有必要的. 接下来,就谈一谈常见的 ...

  9. 【Linux kernel】自旋锁和互斥锁

    内核当发生访问资源冲突的时候,可以有两种锁的解决方案选择: 一个是原地等待 一个是挂起当前进程,调度其他进程执行(睡眠) Linux内核提供了自旋锁和互斥锁的机制,两者都能保证在同一时刻只有一个执行单 ...

最新文章

  1. c语言自定义函数程序设计,ch3自定义函数设计 C语言 《解析C程序设计》.ppt
  2. HTML-参考手册: HTTP 方法:GET 对比 POST
  3. JZOJ 3401 JZOJ 5673. 【GDOI2018Day1模拟4.20】爬山法
  4. hystrix基于request cache请求缓存技术优化批量数据查询接口
  5. mysql不支持emoji表情的问题的解决方法
  6. dimension and x,y,z components
  7. Shiro 常用标签
  8. 字典文件txt下载_qq阅读官方下载-QQ阅读器下载V7.5.0.888官方最新版
  9. android去掉锁屏界面,android怎么去掉锁屏界面
  10. Java web 在线预览--参考二
  11. 基于STM32F4实现FOC(磁场定向控制)一:电流采样和波形产生
  12. x310 跑OAI-developnr
  13. 公有云服务器租赁协议,云服务器
  14. 百度、阿里、腾讯、华为和移动等常用网盘免费空间与性价比
  15. 复选框的全选、全不选、和获取选中的值;
  16. Mac使用Karabiner-Elements修改mac默认快捷键
  17. vue 2.0 图片懒加载
  18. COMSOL中场路耦合(电路接口与电磁场接口)
  19. 微积分-微积分的本质
  20. 我与小娜(20):去LIGO,探秘光子接力赛

热门文章

  1. CPU(中央处理器)和GPU(图像处理器)区别大揭秘
  2. 浅谈tensorflow的指数衰减学习率、正则化、滑动平均模型
  3. 中年危机难解,58同城如何继续“神奇”之路?
  4. ubuntu 12.04 给四个工作区设置不同壁纸
  5. 经典!材料科学基础的思维导图
  6. 强制删除 bat命令
  7. PyCharm打包失败及Pyinstall无法安装问题的解决
  8. DOTA数据集测试mAP
  9. 【PaddleSeg】【天池大赛】真实场景篡改图像检测挑战赛线上2391
  10. 大数据技术在CBTC列车控制系统中的应用