Go 之 sync.Mutex 加锁失效现象

我先声明一下,并不是真的加锁失效,而是我之前的理解有误,导致看起来像是加锁失效一样。于是乎记录一下,加深一下印象。

我之前有个理解误区(不知道大家有没有,有的话赶紧纠正一下——其实也是因为我这块的知识掌握不牢固导致的):觉得只要是加锁后,在我主动调用解锁之前,这个块范围内的变量一定不会被其他地方修改。后来验证发现,我大错特错了。

起因

最近在学习 sync.Mutex 加锁时,写了下面一段代码进行练习。

package mainimport ("fmt""sync""time"
)type Info struct {mu sync.MutexValue string
}func Update(info *Info) {fmt.Printf("%s: before update. Value: %s\n", time.Now().Format(timeFormat), info.Value)info.mu.Lock()defer info.mu.Unlock()time.Sleep(2 * time.Second)fmt.Printf("%s: in update. Value: %s\n", time.Now().Format(timeFormat), info.Value)info.Value = "update"fmt.Printf("%s: after update. Value: %s\n", time.Now().Format(timeFormat), info.Value)
}const timeFormat = "2006-01-02 15:04:05"func main() {fmt.Printf("%s: main start\n", time.Now().Format(timeFormat))info := &Info{}var wg sync.WaitGroupwg.Add(1)go func() {defer wg.Done()Update(info)}()time.Sleep(time.Second)info.Value = "main"fmt.Printf("%s: in main. Value: %s\n", time.Now().Format(timeFormat), info.Value)wg.Wait()
}

按照我原先上面的理解,Update() 函数当中,before update 和 in update 中对应结构体的值应该是不会变的(毕竟我加了锁)。然而从运行结果发现,Update() 函数执行期间,结构体变量的 Value 竟然还是被外部主线程修改了。

分析

那么为什么会这样呢?明明 Update() 里边已经添加了锁,为什么执行期间还是会被其他地方修改呢?

最后发现,究其原因,还是在于主线程修改变量的值的时候,没有先判断锁 mu 是否已经释放,就直接进行了修改操作。

主线程中加上获取锁的操作后,会先判断当前锁是否被释放,如果没被释放,就会一直进行等待直到锁释放后才继续执行后面的操作。

输出结果也和预期保持一致 。

2024-04-16 23:59:13: main start
2024-04-16 23:59:13: before update. Value: 
2024-04-16 23:59:15: in update. Value: 
2024-04-16 23:59:15: after update. Value: update
2024-04-16 23:59:15: in main. Value: main

正常来说,锁是要配合多 goroutine 来使用的, 对于单线程来说,由于没有其他线程进行资源竞争,加锁的意义不大;对于多 goroutine 而言,对于获取和释放锁的时机,应该由应用程序合理控制。关于锁的使用,还有一些其他注意事项,这块也一并写一下。

  • 在一个 goroutine 获得 Mutex 后,其他 goroutine 只能等到这个 goroutine 释放该 Mutex
  • 使用 Lock() 加锁后,不能再继续对其加锁,直到利用 Unlock() 解锁后才能再加锁
  • 在 Lock() 之前使用 Unlock() 会导致 panic 异常
  • 已经锁定的 Mutex 并不与特定的 goroutine 相关联,这样可以利用一个 goroutine 对其加锁,再利用其他 goroutine 对其解锁
  • 在同一个 goroutine 中的 Mutex 解锁之前再次进行加锁,会导致死锁
  • 适用于读写不确定,并且只有一个读或者写的场景

缓冲通道实现互斥逻辑

当然,我们还可以通过缓冲为1的通道实现互斥锁的逻辑。

package mainimport ("fmt""sync""time"
)type Info struct {Value string
}func Update(info *Info, sem chan bool) {fmt.Printf("%s: before update. Value: %s\n", time.Now().Format(timeFormat), info.Value)sem <- truedefer func() {<- sem}()time.Sleep(2 * time.Second)fmt.Printf("%s: in update. Value: %s\n", time.Now().Format(timeFormat), info.Value)info.Value = "update"fmt.Printf("%s: after update. Value: %s\n", time.Now().Format(timeFormat), info.Value)
}const timeFormat = "2006-01-02 15:04:05"func main() {sem := make(chan bool, 1)fmt.Printf("%s: main start\n", time.Now().Format(timeFormat))info := &Info{}var wg sync.WaitGroupwg.Add(1)go func() {defer wg.Done()Update(info, sem)}()time.Sleep(time.Second)sem <- trueinfo.Value = "main"fmt.Printf("%s: in main. Value: %s\n", time.Now().Format(timeFormat), info.Value)<- semwg.Wait()
}
2024-04-17 00:26:25: main start
2024-04-17 00:26:25: before update. Value: 
2024-04-17 00:26:26: in main. Value: main
2024-04-17 00:26:27: in update. Value: main
2024-04-17 00:26:27: after update. Value: update

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/824450.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024年DCMM最新补贴,奖励政策

DCMM&#xff08;数据管理能力成熟度模型&#xff09;认证奖励补贴政策是中国各地政府为了推动企业提升数据管理能力、加快数字化转型而出台的一系列措施。这些政策旨在通过财政资金的激励&#xff0c;鼓励企业进行数据管理能力的提升和认证&#xff0c;从而促进整个地区乃至国…

【在线OJ系统】自定义注解实现分布式ID无感自增

实现思路 首先自定义参数注解&#xff0c;然后根据AOP思想&#xff0c;找到该注解作用的切点&#xff0c;也就是mapper层对于mapper层的接口在执行前都会执行该aop操作&#xff1a;获取到对于的方法对象&#xff0c;根据方法对象获取参数列表&#xff0c;根据参数列表判断某个…

html接入高德地图

1.申请key key申请地址&#xff1a;https://console.amap.com/dev/key/app 官方文档 https://lbs.amap.com/api/javascript-api-v2/summary 2.html接入示例 需要将YOUR_KEY替换成自己的key <!doctype html> <html> <head><meta charset"utf-…

IDEA 安装、基本使用、创建项目

文章目录 下载基本使用修改颜色主题Keymap插件 创建项目创建模块新建 Java 类运行新建 Package打包 Jar运行 jar 包 查看文档 下载 官方下载地址&#xff1a;https://www.jetbrains.com/zh-cn/idea/download/?sectionmac 这里我下载 macOS 社区版&#xff0c;IDEA 2024.1 (C…

arcgis中坡向计算工作原理说明

用于识别出从每个像元到其相邻像元方向上值的变化率最大的下坡方向。坡向可以被视为坡度方向。输出栅格中各像元的值可指示出各像元位置处表面的朝向的罗盘方向。将按照顺时针方向进行测量&#xff0c;角度范围介于 0&#xff08;正北&#xff09;到 360&#xff08;仍是正北&a…

Windows 安装 A UDP/TCP Assistant 网络调试助手

Windows 安装 A UDP/TCP Assistant 网络调试助手 0. 引言1. 下载地址2. 安装和使用 0. 引言 需要调试一个实时在线聊天程序&#xff0c;安装一个UDP/TCP Assistant 网络调试助手&#xff0c;方便调试。 1. 下载地址 https://github.com/busyluo/NetAssistant/releases 2. 安…

力扣练习题(2024/4/17)

1 最长递增子序列 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的 子…

Jsp 中的getServletContext全局数据共享

servletContext作用于不同用户之上 1. 一个用户将数据保存到了servletContext中, // getcontext的servlet程序 Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext context this.get…

考察自动化立体库应注意的几点

导语 大家好&#xff0c;我是智能仓储物流技术研习社的社长&#xff0c;老K。专注分享智能仓储物流技术、智能制造等内容。 整版PPT和更多学习资料&#xff0c;请球友到知识星球 【智能仓储物流技术研习社】自行下载 考察自动化立体仓库的关键因素&#xff1a; 仓库容量&#x…

CentOS的常用命令

1. 系统信息查询与管理 查看系统基本信息 hostnamectl&#xff1a;显示主机名、操作系统版本、内核版本、架构等信息。 hostnamectl uname&#xff1a;显示系统内核与硬件信息。 uname -a # 显示全部信息 lsb_release&#xff1a;显示LSB&#xff08;Linux Standard Base&am…

windows11 wsl2 ubuntu20.04安装vision mamba并进行测试

windows11 wsl2 ubuntu20.04安装vision mamba 安装流程使用cifar-100测试安装成功 安装流程 vision mamba安装了半天才跑通&#xff0c;记录一下流程在wsl上安装cuda wget https://developer.download.nvidia.cn/compute/cuda/11.8.0/local_installers/cuda_11.8.0_520.61.05…

[论文笔记]Root Mean Square Layer Normalization

引言 今天带来论文Root Mean Square Layer Normalization的笔记&#xff0c;论文题目是均方根层归一化。 本篇工作提出了RMSNorm&#xff0c;认为可以省略重新居中步骤。 简介 层归一化对Transformer等模型非常重要&#xff0c;它可以帮助稳定训练并提升模型收敛性&#xf…

【Go】九、API 编写测试_实现一个用户模块的接口

项目构建 New Project 直接创建项目&#xff0c;只需要起名字&#xff0c;之后在根目录中创建对应的微服务&#xff0c;这里先开发用户微服务模块&#xff1a; mxshop_srvs user_srv global 公共内容 handler 服务 model 数据模型&#xff08;表结构对应的模型&#xff09; pr…

NVM下载、NVM配置、NVM常用命令

NVM(nodejs版本管理切换工具)下载、配置、常用命令 0、NVM常用命令 nvm off // 禁用node.js版本管理(不卸载任何东西) nvm on // 启用node.js版本管理 nvm install <version> // 安装node.js的命名 version是版本号 例…

发布!DolphinDB 白皮书正式上线官网!

对广大数据库用户而言&#xff0c;白皮书是极具参考价值的使用指南和学习手册。白皮书不但能深入剖析数据库的基础概念与架构&#xff0c;协助用户了解数据库的工作原理和应用技巧&#xff0c;更提供了丰富的实践案例&#xff0c;帮助用户从中汲取经验&#xff0c;避免在实际应…

【JAVA基础篇教学】第十一篇:Java中字符串操作详解

博主打算从0-1讲解下java基础教学&#xff0c;今天教学第十篇&#xff1a;Java中字符串操作详解。 在 Java 编程中&#xff0c;字符串是一种常见的数据类型&#xff0c;通常用于存储文本信息。Java 提供了丰富的字符串操作方法&#xff0c;可以对字符串进行分割、截取、查找…

【QT进阶】Qt Web混合编程之VS2019 CEF的编译与使用(图文并茂超详细介绍)

往期回顾 【QT入门】Qt自定义控件与样式设计之自定义QLineEdit实现搜索编辑框-CSDN博客 【QT入门】Qt自定义控件与样式设计之自定义QTabWidget实现tab在左&#xff0c;文本水平的效果-CSDN博客【QT进阶】Qt Web混合编程之CEF、QCefView简单介绍-CSDN博客 【QT进阶】Qt Web混合编…

【学习笔记】天元西南中心的线上课程《理解神经网络》

机器学习介绍 introduction machine learning deep learning statistics vs. machine learning 区别&#xff1a;是否存在模型依赖&#xff1b;模型实质由参数组成。 statistics: model based 用训练数据来构建模型&#xff0c;是为了获取模型的参数&#xff0c;参数就是模…

文件msvcr120.dll丢失怎样修复?这三种方法能准确修复msvcr120.dll

小编为大家总结了解决msvcr120.dll文件缺失问题的三种方法&#xff0c;以帮助你快速解决这一难题。首先&#xff0c;我们来看看msvcr120.dll文件为何会出现丢失的情形。 一.msvcr120.dll丢失问题的常见原因包括 病毒感染&#xff1a;病毒或恶意软件侵入电脑有可能会损毁或删除…

【第1节】书生·浦语大模型全链路开源开放体系

目录 1 简介2 内容&#xff08;1&#xff09;书生浦语大模型发展历程&#xff08;2&#xff09;体系&#xff08;3&#xff09;亮点&#xff08;4&#xff09;全链路体系构建a.数据b 预训练c 微调d 评测e.模型部署f.agent 智能体 3 相关论文解读4 ref 1 简介 书生浦语 InternLM…