自旋锁代替互斥锁的实践

2024-06-09 06:32
文章标签 互斥 实践 自旋 代替

本文主要是介绍自旋锁代替互斥锁的实践,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转自:http://ifeve.com/practice-of-using-spinlock-instead-of-mutex/

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

理论分析

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

存在的问题

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

解决方案

在单核/单CPU系统上使用自旋锁是没用的, 因为当线程尝试获取自旋锁不成功的时候会一直尝试, 这会一直占用CPU, 其它线程不可能运行, 因为其他线程不能运行, 这个锁也就不会被解锁。 换句话说, 在单核/单CPU的系统上,自旋锁除了浪费时间没有一点好处。 这时如果这个线程(记为A)可以休眠, 其它线程可以立即运行, 因为其它有可能解锁, 那么线程A可能在唤醒后继续执行。

在多核/多CPU的系统上, 特别是大量的线程只会短时间的持有锁的时候, 在使线程睡眠和唤醒线程上浪费大量的时间, 也许会显著降低程序的运行性能。 使用自旋锁, 线程可以充分利用调度程序分配的时间片(经常阻塞很短的时间, 不用休眠, 然后马上继续它们的工作了), 以达到更高的处理能力和吞吐量。

实践

因为程序员往往并不能事先知道哪种方案会更好(比如, 不知道运行环境的CPU核的数量), 操作系统也不知道一段指令是不是针对单核或者多核环境下做过优化, 所以大部分操作系统并不严格区分互斥锁和自旋锁。 实际上, 绝大部分现代的操作系统采用的是混合型互斥锁(hybrid mutexes)和混合型自旋锁(hybrid spinlocks)。 它们是什么意思呢?

混合型互斥锁, 在多核系统上起初表现的像自旋锁一样, 如果一个线程不能获取互斥锁, 它不会马上被切换为休眠状态, 因为互斥量可能很快就被解锁, 所以这种机制会表现的像自旋锁一样。 只有在一段时间以后(或者尝试一定次数,或者其他指标)还不能获取锁, 它就会被切换为休眠状态。 如果运行在单核/单CPU上, 这种机制将不会自旋(就像上面解释的, 这种情况自旋没有什么好处)。

混合型自旋锁, 起初表现的和正常自旋锁一样, 但是为了避免浪费大量的CPU时间, 会有一个折中的策略。 这种机制不会把线程切换到休眠态(既然想要使用自旋锁, 那么你并不希望这种情况发生), 也许会决定放弃这个线程的执行(马上放弃或者等一段时间)并允许其他线程运行, 这样提高了自旋锁被解锁的可能性(大多数情况, 线程之间的切换操作比使线程休眠而后唤醒它要昂贵, 尽管那不是很明显)。

总结

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

这篇关于自旋锁代替互斥锁的实践的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1044428

相关文章

MySQL 用户创建与授权最佳实践

《MySQL用户创建与授权最佳实践》在MySQL中,用户管理和权限控制是数据库安全的重要组成部分,下面详细介绍如何在MySQL中创建用户并授予适当的权限,感兴趣的朋友跟随小编一起看看吧... 目录mysql 用户创建与授权详解一、MySQL用户管理基础1. 用户账户组成2. 查看现有用户二、创建用户1. 基

Spring Boot 实现 IP 限流的原理、实践与利弊解析

《SpringBoot实现IP限流的原理、实践与利弊解析》在SpringBoot中实现IP限流是一种简单而有效的方式来保障系统的稳定性和可用性,本文给大家介绍SpringBoot实现IP限... 目录一、引言二、IP 限流原理2.1 令牌桶算法2.2 漏桶算法三、使用场景3.1 防止恶意攻击3.2 控制资源

springboot项目中整合高德地图的实践

《springboot项目中整合高德地图的实践》:本文主要介绍springboot项目中整合高德地图的实践,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一:高德开放平台的使用二:创建数据库(我是用的是mysql)三:Springboot所需的依赖(根据你的需求再

SpringBoot3应用中集成和使用Spring Retry的实践记录

《SpringBoot3应用中集成和使用SpringRetry的实践记录》SpringRetry为SpringBoot3提供重试机制,支持注解和编程式两种方式,可配置重试策略与监听器,适用于临时性故... 目录1. 简介2. 环境准备3. 使用方式3.1 注解方式 基础使用自定义重试策略失败恢复机制注意事项

MySQL MCP 服务器安装配置最佳实践

《MySQLMCP服务器安装配置最佳实践》本文介绍MySQLMCP服务器的安装配置方法,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下... 目录mysql MCP 服务器安装配置指南简介功能特点安装方法数据库配置使用MCP Inspector进行调试开发指

SQLite3命令行工具最佳实践指南

《SQLite3命令行工具最佳实践指南》SQLite3是轻量级嵌入式数据库,无需服务器支持,具备ACID事务与跨平台特性,适用于小型项目和学习,sqlite3.exe作为命令行工具,支持SQL执行、数... 目录1. SQLite3简介和特点2. sqlite3.exe使用概述2.1 sqlite3.exe

SQL中JOIN操作的条件使用总结与实践

《SQL中JOIN操作的条件使用总结与实践》在SQL查询中,JOIN操作是多表关联的核心工具,本文将从原理,场景和最佳实践三个方面总结JOIN条件的使用规则,希望可以帮助开发者精准控制查询逻辑... 目录一、ON与WHERE的本质区别二、场景化条件使用规则三、最佳实践建议1.优先使用ON条件2.WHERE用

Springboot整合Redis主从实践

《Springboot整合Redis主从实践》:本文主要介绍Springboot整合Redis主从的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言原配置现配置测试LettuceConnectionFactory.setShareNativeConnect

java中Optional的核心用法和最佳实践

《java中Optional的核心用法和最佳实践》Java8中Optional用于处理可能为null的值,减少空指针异常,:本文主要介绍java中Optional核心用法和最佳实践的相关资料,文中... 目录前言1. 创建 Optional 对象1.1 常规创建方式2. 访问 Optional 中的值2.1

Nginx Location映射规则总结归纳与最佳实践

《NginxLocation映射规则总结归纳与最佳实践》Nginx的location指令是配置请求路由的核心机制,其匹配规则直接影响请求的处理流程,下面给大家介绍NginxLocation映射规则... 目录一、Location匹配规则与优先级1. 匹配模式2. 优先级顺序3. 匹配示例二、Proxy_pa