golang 中 sync.Mutex 和 sync.RWMutex

golang读写锁sync.RWMutex sync.RWMutex提供以下接口: //写锁 func (rw *RWMutex) Lock() //写解锁 func (rw *RWMutex) UnLock() //读锁 func (rw *RWMutex) RLock() //读解锁 func (rw *RWMutex) RUnLock() 规则: ·同一个时间只能有一个goroutine获取到写锁。 ·同一个时间段可以有任意个goroutine获取到读锁。 ·写锁与读锁互斥(即不能同时存在写锁与读锁)。 实例: func ma 阅读详情

转载: https://www.jianshu.com/p/679041bdaa39

介绍

golang 中的 sync 包实现了两种锁:

  • Mutex:互斥锁
  • RWMutex:读写锁,RWMutex 基于 Mutex 实现

Mutex(互斥锁)

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

示例

加锁和解锁示例

package main

import (
    "time"
    "fmt"
    "sync"
)

func main() {
    var mutex sync.Mutex
    fmt.Println("Lock the lock")
    mutex.Lock()
    fmt.Println("The lock is locked")
    channels := make([]chan int, 4)
    for i := 0; i < 4; i++ {
        channels[i] = make(chan int)
        go func(i int, c chan int) {
            fmt.Println("Not lock: ", i)
            mutex.Lock()
            fmt.Println("Locked: ", i)
            time.Sleep(time.Second)
            fmt.Println("Unlock the lock: ", i)
            mutex.Unlock()
            c <- i
        }(i, channels[i])
    }
    time.Sleep(time.Second)
    fmt.Println("Unlock the lock")
    mutex.Unlock()
    time.Sleep(time.Second)

    for _, c := range channels {
        <-c
    }
}

程序输出:

Lock the lock
The lock is locked
Not lock:  1
Not lock:  2
Not lock:  0
Not lock:  3
Unlock the lock
Locked:  1
Unlock the lock:  1
Locked:  2
Unlock the lock:  2
Locked:  3
Unlock the lock:  3
Locked:  0
Unlock the lock:  0

在解锁之前加锁会导致死锁

package main

import (
    "fmt"
    "sync"
)

func main(){
    var mutex sync.Mutex
    mutex.Lock()
    fmt.Println("Locked")
    mutex.Lock()
}

程序输出:

Locked
fatal error: all goroutines are asleep - deadlock!

RWMutex(读写锁)

  • RWMutex 是单写多读锁,该锁可以加多个读锁或者一个写锁
  • 读锁占用的情况下会阻止写,不会阻止读,多个 goroutine 可以同时获取读锁
  • 写锁会阻止其他 goroutine(无论读和写)进来,整个锁由该 goroutine 独占
  • 适用于读多写少的场景

Lock() 和 Unlock()

  • Lock() 加写锁,Unlock() 解写锁
  • 如果在加写锁之前已经有其他的读锁和写锁,则 Lock() 会阻塞直到该锁可用,为确保该锁可用,已经阻塞的 Lock() 调用会从获得的锁中排除新的读取器,即写锁权限高于读锁,有写锁时优先进行写锁定
  • 在 Lock() 之前使用 Unlock() 会导致 panic 异常

RLock() 和 RUnlock()

  • RLock() 加读锁,RUnlock() 解读锁
  • RLock() 加读锁时,如果存在写锁,则无法加读锁;当只有读锁或者没有锁时,可以加读锁,读锁可以加载多个
  • RUnlock() 解读锁,RUnlock() 撤销单词 RLock() 调用,对于其他同时存在的读锁则没有效果
  • 在没有读锁的情况下调用 RUnlock() 会导致 panic 错误
  • RUnlock() 的个数不得多余 RLock(),否则会导致 panic 错误

示例

Lock() 和 Unlock()

package main

import (
    "sync"
    "fmt"
    "time"
)

func main() {
    var mutex *sync.RWMutex
    mutex = new(sync.RWMutex)
    fmt.Println("Lock the lock")
    mutex.Lock()
    fmt.Println("The lock is locked")

    channels := make([]chan int, 4)
    for i := 0; i < 4; i++ {
        channels[i] = make(chan int)
        go func(i int, c chan int) {
            fmt.Println("Not lock: ", i)
            mutex.Lock()
            fmt.Println("Locked: ", i)
            fmt.Println("Unlock the lock: ", i)
            mutex.Unlock()
            c <- i
        }(i, channels[i])
    }
    time.Sleep(time.Second)
    fmt.Println("Unlock the lock")
    mutex.Unlock()
    time.Sleep(time.Second)

    for _, c := range channels {
        <-c
    }
}

程序输出:

Lock the lock
The lock is locked
Not lock:  0
Not lock:  1
Not lock:  2
Not lock:  3
Unlock the lock
Locked:  0
Unlock the lock:  0
Locked:  2
Unlock the lock:  2
Locked:  3
Unlock the lock:  3
Locked:  1
Unlock the lock:  1

Lock() 和 RLock()

package main

import (
    "sync"
    "fmt"
    "time"
)

func main() {
    var mutex *sync.RWMutex
    mutex = new(sync.RWMutex)
    fmt.Println("Lock the lock")
    mutex.Lock()
    fmt.Println("The lock is locked")

    channels := make([]chan int, 4)
    for i := 0; i < 4; i++ {
        channels[i] = make(chan int)
        go func(i int, c chan int) {
            fmt.Println("Not read lock: ", i)
            mutex.RLock()
            fmt.Println("Read Locked: ", i)
            fmt.Println("Unlock the read lock: ", i)
            time.Sleep(time.Second)
            mutex.RUnlock()
            c <- i
        }(i, channels[i])
    }
    time.Sleep(time.Second)
    fmt.Println("Unlock the lock")
    mutex.Unlock()
    time.Sleep(time.Second)

    for _, c := range channels {
        <-c
    }
}

程序输出:

Lock the lock
The lock is locked
Not read lock:  2
Not read lock:  3
Not read lock:  1
Not read lock:  0
Unlock the lock
Read Locked:  2
Read Locked:  1
Unlock the read lock:  2
Unlock the read lock:  1
Read Locked:  0
Read Locked:  3
Unlock the read lock:  0
Unlock the read lock:  3

Unlock() 使用之前不存在 Lock()

package main

import (
    "sync"
)

func main(){
    var rwmutex *sync.RWMutex
    rwmutex = new(sync.RWMutex)
    rwmutex.Unlock()
}

程序输出:

panic: sync: Unlock of unlocked RWMutex

RWMutex 使用不当导致的死锁

示例1:

package main

import (
    "sync"
)

func main(){
    var rwmutex *sync.RWMutex
    rwmutex = new(sync.RWMutex)
    rwmutex.Lock()
    rwmutex.Lock()
}

程序输出:

fatal error: all goroutines are asleep - deadlock!

示例2:

package main

import (
    "sync"
)

func main(){
    var rwmutex *sync.RWMutex
    rwmutex = new(sync.RWMutex)
    rwmutex.Lock()
    rwmutex.RLock()
}

程序输出:

fatal error: all goroutines are asleep - deadlock!

RUnlock() 之前不存在 RLock()

package main

import (
    "sync"
)

func main(){
    var rwmutex *sync.RWMutex
    rwmutex = new(sync.RWMutex)
    rwmutex.RUnlock()
}

程序输出:

panic: sync: RUnlock of unlocked RWMutex

RUnlock() 个数多于 RLock()

package main

import (
    "sync"
)

func main(){
    var rwmutex *sync.RWMutex
    rwmutex = new(sync.RWMutex)
    rwmutex.RLock()
    rwmutex.RLock()
    rwmutex.RUnlock()
    rwmutex.RUnlock()
    rwmutex.RUnlock()
}

程序输出:

panic: sync: RUnlock of unlocked RWMutex



作者:WangZZ
链接:https://www.jianshu.com/p/679041bdaa39
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

 

golang_锁: sync.RWMutex读写锁的用法介绍 sync.RWMutex 读写锁 type RWMutex struct { // 包含隐藏或非导出字段 } RWMutex是读写互斥锁。该锁可以被同时多个读取者持有或唯一个写入者持有。RWMutex可以创建为其他结构体的字段;零值为解锁状态。RWMutex类型的锁也和线程无关,可以由不同的线程加读取锁/写入和解读取锁/写入锁。 Lock func (rw *RWMutex) Lo... 阅读详情

相关推荐

Go 互斥锁(sync.Mutex)和读写锁(sync.RWMutex)性能分析

唤醒的 goroutine 不会直接拥有锁,而是会和新请求锁的 goroutine 竞争锁的拥有。这种锁称之为 多读单写锁 (multiple readers, single writer lock),简称读写锁,读写锁分为读锁和写锁,读锁是允许同时执行的,但写锁是互斥的。读写锁的存在是为了解决读多写少时的性能问题,读场景较多时,读写锁可有效地减少锁阻塞的时间。读锁之间不互斥,没有写锁的情况下,读锁是无阻塞的,多个协程可以同时获得读锁。写锁与读锁是互斥的,如果存在读锁,写锁阻塞,如果存在写锁,读锁阻塞。

FeelTouch Labs 1472

golang源代码阅读,sync系列-读写互斥锁RWMutex

读写互斥锁

u014763610的博客 489

华为无线WiFi实战:基于802.1x与NPS的企业级认证部署指南

本文提供了一份详尽的华为无线WiFi企业级认证部署实战指南。通过整合802.1x协议与Windows NPS服务器,构建基于AD域账号的安全认证体系,彻底解决传统WiFi密码共享带来的安全风险。文章详细拆解了从NPS服务器配置、证书部署到华为AC端RADIUS模板、AAA方案、认证域及VAP模板调用的全流程,并附有终端连接测试与常见故障排查方法,助力企业实现高效、安全的无线网络接入管理。

weixin_29239661的博客 271

Golang深入浅出之-互斥锁(sync.Mutex)与读写锁(sync.RWMutex)

理解和正确使用互斥锁(sync.Mutex)与读写锁()是编写并发安全Go程序的基础。互斥锁确保同一时刻只有一个goroutine访问资源,适用于写多或读写均衡的场景。读写锁优化了读取操作,允许多个读取者同时访问资源,适用于读多写少的场景。避免忘记解锁、重复解锁、混淆读写锁与互斥锁,以及试图升级或降级锁。利用defer语句确保解锁操作的正确执行,提高代码可读性和健壮性。通过遵循这些原则,您将在Go并发编程中有效地利用锁机制,构建安全、高效的并发应用程序。

zevjay的博客 753

动态数据脱敏技术分析

在当前国内信息安全热潮中,数据脱敏作为数据安全的重要一环得到了业界的认可与重视。早在2012年,数据脱敏首次作为一个单独的魔力象限由Gartner发布,Gartner在2014年又提出了:按照数据使用场景,将数据脱敏分为静态数据脱敏(Static data masking-SDM )与动态数据脱敏(Dynamic data masking-DDM )。 可能有人望文生义,认为动态数据脱敏一定比静态数据脱敏高级。非也非也,静态or动态,取决于脱敏的使用场景,主要是以使用场景为由来选择合适的数据脱敏的模式。 本

美创科技的博客 4676

【现代电路理论】【2】考尔法设计无源单口网络

夏 弥:其实你在冰面上看到鱼浮上来 明年冬天如果你还在那里,那鱼还是会上来换气 那时候你就可以带一把冰镐 把冰面砸开把鱼捞上来熬汤

痛苦的时候装出幸福相,这不是那么难做到的事 2886

逐步学习Go-sync.RWMutex(读写锁)-深入理解与实战

Go中提供了读写锁:sync.RWMutex。sync.RWMutex是Go语言提供的一个基础同步原语,它是Reader/Writer Mutual Exclusion Lock的缩写,通常被称为"读写锁"。读写锁允许多个读锁同时拥有者,但在任何时间点只允许一个写锁拥有者,或者没有锁拥有者。

fofcn的专栏 2601

YOLOv8模型INT8量化实战:解决sigmoid输出归零的坑(附代码修改)

本文详细介绍了YOLOv8模型INT8量化过程中遇到的sigmoid输出归零问题及其解决方案。通过修改模型导出代码、优化ONNX量化流程,并提供完整的部署优化技巧,帮助开发者在边缘计算设备上实现高效的模型推理。文章还包含量化效果验证和常见问题排查方法,助力开发者快速解决实际部署中的难题。

vvv99的博客 253

golang中sync.RWMutex和sync.Mutex区别

golang中sync包实现了两种锁Mutex (互斥锁)和RWMutex(读写锁),其中RWMutex是基于Mutex实现的,只读锁的实现使用类似引用计数器的功能. type Mutex     func (m *Mutex) Lock()    func (m *Mutex) Unlock()type RWMutex    func (rw *RWMutex) Lock()    fu

chenbaoke的专栏 4万+

C51编程25-应用篇(单片机与电脑端实现wifi通讯)

单片机使用ESP-01S wifi模块与电脑端进行数据通讯。

qq_34343637的博客 1万+

航天设备研制中的形态分类:电性件、正样件及其他关键形态详解

航天设备的研制是一个高度复杂且严谨的工程过程,涉及多个阶段的不同产品形态。这些形态各具特点,在研制流程中承担着不同的验证任务和工程目标。本文将系统介绍航天设备研制中的主要形态,包括**电性件(EM)**、**正样件(FM)**以及**结构热控件(STM)**、**鉴定件(QM)**和**初样件(PFM)**等,详细解析它们的定义、用途和工程意义,帮助读者全面理解航天产品从设计到飞行的全生命周期管理。

ScilogyHunter的博客 1661

【golang/go语言】sync同步包中Mutex、RWMutex、WaitGroup、Once、Cond、Pool和Map

1. WaitGroup等待组 WaitGroup通过一个计数器counter来让主协程在还有子协程运行的时候进行等待 wg.Add(num)函数可以让counter的值加上具体数值 wg.Wait()函数可以让主协程进入阻塞状态 wg. Done()函数可以让counter的值减一,相当于Add(-1) package main import ( "fmt" "sync" ) var wg sync.WaitGroup func main() { wg.Add(2) go func1()

zuzhiang的博客 1261

华为OD机试双机位C卷:补种未成活胡杨 (C/C++/Py/Java/Js/Go)

华为OD机试双机位C卷 补种未成活胡杨,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解。华为OD机试 - 补种未成活胡杨。

qq_45776114的博客 4007

Go 并发同步原语:sync.Mutex、sync.RWMutex 和 sync.Once

本文介绍了Go语言中三种常用的并发同步原语:sync.Mutex、sync.RWMutex和sync.Once。sync.Mutex提供基本的互斥锁功能,确保同一时间只有一个goroutine访问共享资源;sync.RWMutex是读写锁,适用于读多写少的场景,提高并发性能;sync.Once保证操作只执行一次,常用于单例模式。文章详细说明了它们的使用场景、注意事项和实现原理,强调正确使用同步原语对编写安全高效并发程序的重要性。通过对比分析,帮助开发者理解如何根据具体需求选择合适的同步机制。

qq_33665793的博客 1342

【占用网络】OccNet: Scene as Occupancy 适用于检测、分割和规划任务 ICCV2023

本文分享“占用网络”方案中,具有代表性的方法:OccNet。它以多视角视觉为核心,首先生成BEV特征,然后通过级联结构和时间体素解码器重建生成3D占用特征。构建一个通用的“3D占用编码特征”,用以表示3D物理世界。这样的特征描述可以应用于广泛的自动驾驶任务,包括检测、分割和规划。

黎国溥 3362

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Go的sync包下Mutex和RWMutex源码个人解读

简单一点的理解锁就是一个状态值,比如0表示未加锁,1表示已加锁。上锁操作就是把状态值从0改成1,解锁操作就是把状态值从1改成0。如果修改失败就表明锁的掌控权不在你手上。一个优秀的工具需要具备探测并适应环境,从而采取不同的对策因地制宜的能力。现在有两种策略:优势:无需阻塞协程,短期来看操作较轻劣势:长时间争而不得会浪费CPU时间片适用场景:并发竞争强度低的场景优势:精准打击,不浪费CPU时间片劣势:需要挂起协程,进行上下文切换,操作较重适用场景:并发竞争激烈场景sync.Mutex结合两种方案的使用场景,制定

qq_58339096的博客 469

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

golang中sync.RWMutex和sync.Mutex

golang中sync.RWMutex和sync.Mutex区别 转自:http://blog.csdn.net/chenbaoke/article/details/41957725 golang中sync包实现了两种锁Mutex (互斥锁)和RWMutex(读写锁),其中RWMutex是基于Mutex实现的,只读锁的实现使用类似引用计数器的功能. type Mutex     f

yueguanyun的专栏 1059

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

Go语言并发控制:sync.Mutex、sync.RWMutex和sync.WaitGroup详解

Go语言并发控制:sync.Mutex、sync.RWMutex和sync.WaitGroup详解

一起coding,一起嗨。 833

Go中的锁机制大揭秘:sync.Mutex 和 RWMutex 源码拆解

如何在保证数据一致性的前提下,最大化并发性能,是每个 Go 开发者都必须面对的挑战。Go 的锁机制是现代并发编程的杰作,它在简单性和性能之间找到了完美的平衡。通过深入理解其设计原理和实现细节,我们不仅能写出更高效的并发程序,更能在面对复杂的并发问题时游刃有余。当必须使用锁时,选择合适的锁类型,优化锁的使用方式,并建立完善的监控体系。是最核心的两个锁机制。它们不仅保证了数据的一致性,还通过精巧的设计实现了高性能的并发控制。如果使用普通的互斥锁,即使是并发的读操作也必须串行执行,这显然是对性能的浪费。

m0_54332036的博客 531

Go 互斥锁(sync.Mutex)和 读写锁(sync.RWMutex)

Go 互斥锁(sync.Mutex)和 读写锁(sync.RWMutex) 什么时候需要用到锁?互斥锁(sync.Mutex)读写锁(sync.RWMutex)互斥锁和读写锁的性能对比1)使用互斥锁:2)使用读写锁结论关于互斥锁的补充关于读写锁的补充 什么时候需要用到锁? 当程序中就一个线程的时候,是不需要加锁的,但是通常实际的代码不会只是单线程,所以这个时候就需要用到锁了,那么关于锁的使用场景主要涉及到哪些呢? 多个线程在读相同的数据时 多个线程在写相同的数据时 同一个资源,有读又有写 互斥锁(syn

java_xxxx的博客 1123

Go语言互斥锁(sync.Mutex)和读写互斥锁(sync.RWMutex)

Go语言包中的sync包提供了两种锁类型:sync.Mutex和sync.RWMutex。 Mutex是最简单的一种类型,同时也比较暴力,当一个goroutine获得Mutex后,其他goroutine就只能乖乖等待这个goroutine释放该Mutex. RWMutex 相对友好些,是经典的单写多读模型。在读锁占用的情况下,会阻止写,但不阻止读,也就是多个 goro...

zuiyijiangnan的博客 498

Go语言互斥锁(sync.Mutex)和读写互斥锁(sync.RWMutex)

Go语言包中的 sync 包提供了两种锁类型:sync.Mutex 和 sync.RWMutex。 Mutex 是最简单的一种锁类型,同时也比较暴力,当一个 goroutine 获得了 Mutex 后,其他 goroutine 就只能乖乖等到这个 goroutine 释放该 Mutex。 RWMutex 相对友好些,是经典的单写多读模型。在读锁占用的情况下,会阻止写,但不阻止读,也就是多个 goroutine 可同时获取读锁(调用 RLock() 方法;而写锁(调用 Lock() 方法)会阻止任何其他

xyz的专栏 391

GOLANG sync.Mutex和sync.RWMutex

Package sync type Mutex A Mutex is a mutual exclusion lock. Mutexes can be created as part of other structures; the zero value for a Mutex is an unlocked mutex. A Mutex must not be copied

技术成就梦想,梦想成就未来。If you try hard enough, it can be. 1993

golang锁知识之 sync.Mutex 和 sync.RWMutex

当我们的程序就一个线程的时候是不需要用到锁的,但是通常我们实际的代码不会是单个线程的,所有这个时候就需要用到锁了,那么关于锁的使用场景主要涉及到哪些呢? 当我们多个线程在读相同的数据的时候则是需要加锁的 当我们的程序既有读又有写的时候更是需要加锁的 当我们有多个线程在写的时候同样也是需要加锁 互斥锁 互斥锁:同一个时刻只有一个线程能够拿到锁 我们先通过一个例子来演示,如果当多个线程同时更改一个...

小白菜的专栏 763
上一篇: MYSQL千万级大数据SQL查询优化
下一篇: SpringBoot中获取spring.profiles.active的值
琅琊山二当家
博客等级 码龄18年 447粉丝 322原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值