Bruce Blog Bruce Blog
首页
  • CentOS
  • Ubuntu-Debian
  • 系统网络
  • 系统辅助工具
  • MySQL
  • Redis
  • Mongodb
  • Docker基础
  • Container基础
  • Kubernetes

    • Kubernetes基础
    • Kubernetes辅助
  • Container-Network
  • Jenkins
  • Gitlab
  • ArgoCD
  • Ansible
  • Terraform
  • AWS
  • MQ
  • NGINX
  • JumpServer
  • 基础
  • 函数模块
  • 框架
  • 基础

    • Golang环境
    • 语法
    • 数据类型与运算符
    • 分支语句
    • 循环语句
    • 数组
    • 切片
    • Map
    • String
    • 函数
    • 包的管理
    • 指针
    • 结构体
    • Go语言中的OOP
    • 方法和接口
    • 错误处理
  • Go进阶

    • Go进阶
  • Go框架

    • Go框架
  • Golang辅助

    • Golang辅助
  • CSS
  • HTML
  • JavaScript
  • 前端辅助
  • 常用命令
  • 性能监控工具
  • Windows下Docker使用
  • 日常学习
  • 其他导航

Bruce Tao

运维界的该溜子
首页
  • CentOS
  • Ubuntu-Debian
  • 系统网络
  • 系统辅助工具
  • MySQL
  • Redis
  • Mongodb
  • Docker基础
  • Container基础
  • Kubernetes

    • Kubernetes基础
    • Kubernetes辅助
  • Container-Network
  • Jenkins
  • Gitlab
  • ArgoCD
  • Ansible
  • Terraform
  • AWS
  • MQ
  • NGINX
  • JumpServer
  • 基础
  • 函数模块
  • 框架
  • 基础

    • Golang环境
    • 语法
    • 数据类型与运算符
    • 分支语句
    • 循环语句
    • 数组
    • 切片
    • Map
    • String
    • 函数
    • 包的管理
    • 指针
    • 结构体
    • Go语言中的OOP
    • 方法和接口
    • 错误处理
  • Go进阶

    • Go进阶
  • Go框架

    • Go框架
  • Golang辅助

    • Golang辅助
  • CSS
  • HTML
  • JavaScript
  • 前端辅助
  • 常用命令
  • 性能监控工具
  • Windows下Docker使用
  • 日常学习
  • 其他导航
  • 基础

  • Go进阶

    • Go进阶
    • File操作
    • IO操作
    • 文件复制
    • 断点续传
    • bufio包
    • ioutil包
    • 遍历目录
    • 并发性Concurrency概念
    • Goroutine初识
    • Goroutine并发模型
    • Runtime包
    • 临界资源安全问题
    • sync包WaitGroup
    • 互斥锁
    • 读写锁
      • Channel通道
      • 关闭通道和通道上范围循环
      • 缓冲通道
      • 定向通道
      • time包中的通道相关函数
      • select语句
      • CSP并发模型
      • Go语言反射(一)
      • Go语言反射(二)
    • Go框架

    • Golang辅助

    • Golang
    • Go进阶
    Bruce
    2022-12-03
    目录

    读写锁

    # 一、sync包 --- 读写锁

    • https://golang.google.cn/pkg/sync/#RWMutex

    官方文件sync的介绍

    Package sync provides basic synchronization primitives such as mutual exclusion locks. Other than the Once and WaitGroup types, most are intended for use by low-level library routines. Higher-level synchronization is better done via channels and communication
    
    1

    image-20221123233942416

    sync是synchronization同步这个词的缩写,所以也会叫做同步包.这里提供了基本同步的操作,比如互斥锁等等.这里除了Once和WaitGroup类型之外,大多数类型都是供低级库例教程使用的.更高级别同步最好通过channel通道和communication通信来完成

    image-20221124163204110

    # 二、RWMutex(读写锁)

    Go语言包中的sync包提供了两种类型: sync.Mutex和sync.RWMutex.其中RWMutex基于Mutex实现的,只读锁的实现使用类似引用计数器的功能.

    RWMutex是读/写互斥锁.锁可以由任意数量的读取器或单个编写器持有.RWMutex的零值是未锁的mutex.

    如果一个goroutine持有有一个rRWMutex进行读取,而另一个goroutine可能调用lock,那么在释放初始读取锁之前,任何goroutine都不应该期望能够读取锁.特别是,这禁止递归读取锁定.这是为了确保锁最终可用;被阻止的锁调用会将新的读卡器排除在获取锁之外.

    image-20221124163750557

    怎么理解读写锁呢?当有一个goroutine获得写锁定,其他无论是读锁还是写锁都将阻塞直到写解锁;当有一个goroutine获得读锁定,其读锁定仍然可以继续;当一个或任意多个读锁定,写锁定将等待所有读锁解锁之后才能够进行写锁定.所以说这里的读锁定(RLock)目的其实是告诉锁定: 有很多人在读取数据,需要靠边等待,等它们读(读解锁)完再来写(写锁定).可以将其总结为如下三条:

    • 1.同时只能有一个goroutine能够获得写锁定.
    • 2.同时可以有任意多个gorontine获得读锁定
    • 3.同时只能存在写锁定或读锁定(读和写互斥).

    所以,RWMutex写个读写锁,该锁可以加多个读锁或者一个写锁,其经常用于读写次数远远多于写次数的场景.

    基本遵循两个原则:

    • 1.可以随便读,多个goroutine同时读.
    • 2.写的时候,啥也不能干.不能读也不能写.

    读写锁即是对于读写操作的互斥锁.它有普通的互斥锁最大的不同就是,它可以分别针对读操作和写操作进行锁定和解锁操作.读写锁遵循的访问控制规则与互斥锁有所不同.在读写锁管辖的范围内,它允许任意个读操作的同时进行.但是同一时刻,它只允许有一个写操作在进行.

    并且在某一个写操作被进行的过程中,读操作的进行也是不被允许的.也就是说读写锁控制下的多个写操作之间是互斥的,并且写操作与读操作之间也都是互斥的.但是,多个读操作之间却存在互斥关系.

    # 三、常用方法

    # RLock()方法
    func (rw *RWMutex) RLock()
    
    1

    读锁,当有写锁时,无加载读锁,当只有读锁或者没有锁时,可以加载读锁,读锁可以加载多个,所以适用于"读多写少"的场景.

    image-20221124165106161

    # RUnlock()方法
    func(rw *RWMutex) RUnlock()
    
    1

    读锁解锁,RUnlock撤销单次RLock调用,它对于其他同时存在的读取器则没有效果,若rw并没有为读取而锁定,调用RUnlock就会引发一个运行时的错误.

    image-20221124165404180

    # Lock()方法
    func (rw *RWMutex) Lock()
    
    1

    写锁,如果在添加写锁之前已经有其他的读锁和写锁,则Lock就会阻塞直到该锁可用,为确保该锁最终可用,已阻塞的Lock调用会从获得的锁中排除新的读取锁,即写锁权限高于读锁,有写锁时优先进行写锁定.

    image-20221124165758766

    # Unlock()方法
    func (rw *RWMutex) Unlock()
    
    1

    写锁解锁,如果没有进行写锁定,则就会引起一个运行时错误.

    image-20221124165949146

    # 四、示例代码

    package main
    
    import (
        "fmt"
        "sync"
        "time"
    )
    
    var rwMutex *sync.RWMutex
    var wg *sync.WaitGroup
    func main() {
        rwMutex = new(sync.RWMutex)
        wg = new (sync.WaitGroup)
    
        //wg.Add(2)
        //
        ////多个同时读取
        //go readData(1)
        //go readData(2)
    
        wg.Add(3)
        go writeData(1)
        go readData(2)
        go writeData(3)
    
        wg.Wait()
        fmt.Println("main..over...")
    }
    
    func writeData(i int){
        defer wg.Done()
        fmt.Println(i,"开始写:write start。。")
        rwMutex.Lock()//写操作上锁
        fmt.Println(i,"正在写:writing。。。。")
        time.Sleep(3*time.Second)
        rwMutex.Unlock()
        fmt.Println(i,"写结束:write over。。")
    }
    
    func readData(i int) {
        defer wg.Done()
    
        fmt.Println(i, "开始读:read start。。")
    
        rwMutex.RLock() //读操作上锁
        fmt.Println(i,"正在读取数据:reading。。。")
        time.Sleep(3*time.Second)
        rwMutex.RUnlock() //读操作解锁
        fmt.Println(i,"读结束:read over。。。")
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50

    执行结果

    image-20221124171206613

    image-20221124172744264

    上次更新: 2024/04/09, 16:48:42
    互斥锁
    Channel通道

    ← 互斥锁 Channel通道→

    最近更新
    01
    AWS NAT-NetWork-Firwalld配置(一)
    04-09
    02
    AWS NAT-NetWork-Firwalld配置(二)
    04-09
    03
    kubernetes部署minio对象存储
    01-18
    更多文章>
    Theme by Vdoing | Copyright © 2019-2024 Bruce Tao Blog Space | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式