Go语言中的互斥锁(Mutex)和读写锁(RWMutex)

2024-04-10 00:44

本文主要是介绍Go语言中的互斥锁(Mutex)和读写锁(RWMutex),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 Mutex

  Mutex结构体

type Mutex struct {state int32 //表示互斥锁的状态,比如是否被锁定等sema uint32 //表示信号里,协程阻塞等待的信号量,解锁的协程释放信号量从而唤醒等待信号量的协程
}

  • Locked: 表示Mutex是否已被锁定(1表示已经被锁定)
  • Woken: 表示是否有协程被唤醒(1已有协程唤醒,正在加锁过程中)
  • Starving: 表示Mutex是否处于饥饿状态(1表示饥饿状态,说明有协程阻塞超过1ms)
  • Waiter: 表示阻塞等待锁的协程个数,协程解锁时根据此值来判断是否需要释放洗好了.

协程之间抢锁实际上是抢给Locked赋值的权利,能给Locked值置为1,就说明抢锁成功.抢不到的话就阻塞等待Mutex.sema信号量,一旦持有锁的协程解锁,等到的协程就会被依次唤醒.

Mutex只有两个方法:

  • Lock()加锁
  • Unlock()解锁

加锁被阻塞以及解锁唤醒协程

自旋(CPU的"PAUSE"指令,CPU空转,什么也不做)

加锁时,如果当前Locked为1,说明该锁由其他协程持有,尝试加锁的协程并不是马上转入阻塞,而是会持续的探测Locked位是否变为0,这个过程即为自旋过程.自旋时间很短,但如果自旋过程中发现锁已经被释放,那么协程可以立即获取锁.(可以避免协程间的切片)

Mutex模式

 normal模式

默认情况下,Mutex的模式位normal,该模式下,协程如果加锁不成功不会立即转入阻塞排队,而是判断是否满足自旋条件,如果满足则会启动自旋过程,抢锁.

 starvation模式

自旋过程中能抢到锁的话,说明此时一定有协程释放了锁,释放锁时如果发现有阻塞等待的协程,还会释放一个信号量来唤醒一个等待协程,被唤醒的协程获得CPU开始运行,此时发现锁被抢占,自己再次阻塞,但是如果阻塞时间已经超过1ms,starving将被标记为1(饥饿模式)

饥饿模式下,不会启动自旋过程.

Woken状态

Woken状态用于加锁和解锁过程的通信.

读写锁

type RWMutex struct {w           Mutex  //用于控制多个写锁,获得写锁首先要获取该锁,如果有一个写锁在进行,那么再到来的写锁将会阻塞于此writerSem   uint32 //写阻塞等待的信号量,最后一个读者释放锁时会释放信号量readerSem   uint32 //读阻塞的协程等待的信号量,持有写锁的协程释放锁后会释放信号量readerCount int32  //记录读者个数readerWait  int32  //记录写阻塞时读者个数
}
接口定义
  • RLock(): 读锁定,等待写操作结束(如果有)
  • RUnlock(): 解除读锁定,唤醒等待写操作的协程(如果有)
  • Lock(): 写锁定,与Mutex完全一致,阻塞等待所有读操作结束(如果有)
  • Unlock(): 解除写锁定,与Mutex一致,唤醒因读锁定而被阻塞的协程(如果有)

这篇关于Go语言中的互斥锁(Mutex)和读写锁(RWMutex)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

Go路由注册方法详解

《Go路由注册方法详解》Go语言中,http.NewServeMux()和http.HandleFunc()是两种不同的路由注册方式,前者创建独立的ServeMux实例,适合模块化和分层路由,灵活性高... 目录Go路由注册方法1. 路由注册的方式2. 路由器的独立性3. 灵活性4. 启动服务器的方式5.

Go语言中三种容器类型的数据结构详解

《Go语言中三种容器类型的数据结构详解》在Go语言中,有三种主要的容器类型用于存储和操作集合数据:本文主要介绍三者的使用与区别,感兴趣的小伙伴可以跟随小编一起学习一下... 目录基本概念1. 数组(Array)2. 切片(Slice)3. 映射(Map)对比总结注意事项基本概念在 Go 语言中,有三种主要

Go Mongox轻松实现MongoDB的时间字段自动填充

《GoMongox轻松实现MongoDB的时间字段自动填充》这篇文章主要为大家详细介绍了Go语言如何使用mongox库,在插入和更新数据时自动填充时间字段,从而提升开发效率并减少重复代码,需要的可以... 目录前言时间字段填充规则Mongox 的安装使用 Mongox 进行插入操作使用 Mongox 进行更

C语言中自动与强制转换全解析

《C语言中自动与强制转换全解析》在编写C程序时,类型转换是确保数据正确性和一致性的关键环节,无论是隐式转换还是显式转换,都各有特点和应用场景,本文将详细探讨C语言中的类型转换机制,帮助您更好地理解并在... 目录类型转换的重要性自动类型转换(隐式转换)强制类型转换(显式转换)常见错误与注意事项总结与建议类型

Go语言利用泛型封装常见的Map操作

《Go语言利用泛型封装常见的Map操作》Go语言在1.18版本中引入了泛型,这是Go语言发展的一个重要里程碑,它极大地增强了语言的表达能力和灵活性,本文将通过泛型实现封装常见的Map操作,感... 目录什么是泛型泛型解决了什么问题Go泛型基于泛型的常见Map操作代码合集总结什么是泛型泛型是一种编程范式,允

Android kotlin语言实现删除文件的解决方案

《Androidkotlin语言实现删除文件的解决方案》:本文主要介绍Androidkotlin语言实现删除文件的解决方案,在项目开发过程中,尤其是需要跨平台协作的项目,那么删除用户指定的文件的... 目录一、前言二、适用环境三、模板内容1.权限申请2.Activity中的模板一、前言在项目开发过程中,尤

C语言小项目实战之通讯录功能

《C语言小项目实战之通讯录功能》:本文主要介绍如何设计和实现一个简单的通讯录管理系统,包括联系人信息的存储、增加、删除、查找、修改和排序等功能,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录功能介绍:添加联系人模块显示联系人模块删除联系人模块查找联系人模块修改联系人模块排序联系人模块源代码如下

基于Go语言实现一个压测工具

《基于Go语言实现一个压测工具》这篇文章主要为大家详细介绍了基于Go语言实现一个简单的压测工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录整体架构通用数据处理模块Http请求响应数据处理Curl参数解析处理客户端模块Http客户端处理Grpc客户端处理Websocket客户端

Go中sync.Once源码的深度讲解

《Go中sync.Once源码的深度讲解》sync.Once是Go语言标准库中的一个同步原语,用于确保某个操作只执行一次,本文将从源码出发为大家详细介绍一下sync.Once的具体使用,x希望对大家有... 目录概念简单示例源码解读总结概念sync.Once是Go语言标准库中的一个同步原语,用于确保某个操