Go 互斥锁和读写互斥锁的实现

目录
  • 互斥锁
  • 读写互斥锁

先来看这样一段代码,所存在的问题:

var wg sync.WaitGroup
var x int64

func main() {
 wg.Add(2)
 go f()
 go f()
 wg.Wait()
 fmt.Println(x) // 输出:12135
}

func f()  {
 for i:=0;i<10000;i++ {
  x = x+1
 }
 wg.Done()
}

这里为什么输出是 12135(不同的机器结果不一样),而不是20000。

因为 x 的赋值,总共分为三个步骤:取出x的值、计算x的结果、给x赋值。那么由于对于f函数的调用采用了goroutine协程,所以存在资源竞争的问题,所以有赋值和计算过程中存在脏数据。对于此类的问题,可以采用互斥锁解决:

互斥锁

互斥锁是一种常用的控制共享资源访问的方法,它能够保证同时只有一个goroutine可以访问共享资源。Go语言中使用sync包的Mutex类型来实现互斥锁。

var wg sync.WaitGroup
var x int64
var lock sync.Mutex

func main() {
 wg.Add(2)
 go f()
 go f()
 wg.Wait()
 fmt.Println(x) // 输出:20000
}

func f()  {
 for i:=0;i<10000;i++ {
  lock.Lock() // 加互斥锁
  x = x+1
  lock.Unlock() // 解锁
 }
 wg.Done()
}

使用互斥锁能够保证同一时间有且只有一个goroutine进入临界区,其他的goroutine则在等待锁;当互斥锁释放后,等待的goroutine才可以获取锁进入临界区,多个goroutine同时等待一个锁时,唤醒的策略是随机的。

读写互斥锁

互斥锁是完全互斥的,但是有很多实际的场景下是读多写少的,当我们并发的去读取一个资源不涉及资源修改的时候是没有必要加锁的,这种场景下使用读写锁是更好的一种选择。读写锁在Go语言中使用sync包中的RWMutex类型。

读写锁分为两种:读锁和写锁。当一个goroutine获取读锁之后,其他的goroutine如果是获取读锁会继续获得锁,如果是获取写锁就会等待;当一个goroutine获取写锁之后,其他的goroutine无论是获取读锁还是写锁都会等待。

var (
 x1 int64
 wg1 sync.WaitGroup
 lock1 sync.Mutex
 rwlock sync.RWMutex
)

func main() {
 startTime := time.Now()
 for i:=0;i<100;i++ {
  wg1.Add(1)
  write()
 }
 for i:=0;i<10000;i++ {
  wg1.Add(1)
  read()
 }
 wg1.Wait()
 fmt.Println(time.Now().Sub(startTime))

 // 互斥锁用时: 973.9304ms
 // 读写互斥锁用时: 718.094ms
}

func read()  {
 defer wg1.Done()
 //lock1.Lock() // 互斥锁
 rwlock.RLock() // 读写互斥锁
 fmt.Println(x1)
 //lock1.Unlock() // 互斥锁
 rwlock.RUnlock() // 读写互斥锁
}

func write()  {
 defer wg1.Done()
 lock1.Lock()
 x1 = x1+1
 lock1.Unlock()
}

到此这篇关于Go 互斥锁和读写互斥锁的实现的文章就介绍到这了,更多相关Go 互斥锁和读写互斥锁内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • GO语言并发编程之互斥锁、读写锁详解

    在本节,我们对Go语言所提供的与锁有关的API进行说明.这包括了互斥锁和读写锁.我们在第6章描述过互斥锁,但却没有提到过读写锁.这两种锁对于传统的并发程序来说都是非常常用和重要的. 一.互斥锁 互斥锁是传统的并发程序对共享资源进行访问控制的主要手段.它由标准库代码包sync中的Mutex结构体类型代表.sync.Mutex类型(确切地说,是*sync.Mutex类型)只有两个公开方法--Lock和Unlock.顾名思义,前者被用于锁定当前的互斥量,而后者则被用来对当前的互斥量进行解锁. 类型sy

  • 详解Golang互斥锁内部实现

    go语言提供了一种开箱即用的共享资源的方式,互斥锁(sync.Mutex), sync.Mutex的零值表示一个没有被锁的,可以直接使用的,一个goroutine获得互斥锁后其他的goroutine只能等到这个gorutine释放该互斥锁,在Mutex结构中只公开了两个函数,分别是Lock和Unlock,在使用互斥锁的时候非常简单,本文并不阐述使用. 在使用sync.Mutex的时候千万不要做值拷贝,因为这样可能会导致锁失效.当我们打开我们的IDE时候跳到我们的sync.Mutex 代码中会发现

  • Go语言并发编程之互斥锁Mutex和读写锁RWMutex

    目录 一.互斥锁Mutex 1.Mutex介绍 2.Mutex使用实例 二.读写锁RWMutex 1.RWMutex介绍 2.RWMutex使用实例 在并发编程中,多个Goroutine访问同一块内存资源时可能会出现竞态条件,我们需要在临界区中使用适当的同步操作来以避免竞态条件.Go 语言中提供了很多同步工具,本文将介绍互斥锁Mutex和读写锁RWMutex的使用方法. 一.互斥锁Mutex 1.Mutex介绍 Go 语言的同步工具主要由 sync 包提供,互斥锁 (Mutex) 与读写锁 (R

  • 详解golang RWMutex读写互斥锁源码分析

    针对Golang 1.9的sync.RWMutex进行分析,与Golang 1.10基本一样除了将panic改为了throw之外其他的都一样. RWMutex是读写互斥锁.锁可以由任意数量的读取器或单个写入器来保持. RWMutex的零值是一个解锁的互斥锁. 以下代码均去除race竞态检测代码 源代码位置:sync\rwmutex.go 结构体 type RWMutex struct { w Mutex // 互斥锁 writerSem uint32 // 写锁信号量 readerSem uin

  • Go语言并发编程 互斥锁详情

    目录 1.互斥锁Mutex 1.1 Mutex介绍 1.2 Mutex使用实例 2.读写锁RWMutex 2.1 RWMutex介绍 2.2 RWMutex使用实例 1.互斥锁Mutex 1.1 Mutex介绍 Go 语言的同步工具主要由 sync 包提供,互斥锁 (Mutex) 与读写锁 (RWMutex) 就是sync 包中的方法. 互斥锁可以用来保护一个临界区,保证同一时刻只有一个 goroutine 处于该临界区内.主要包括锁定(Lock方法)和解锁(Unlock方法)两个操作,首先对进

  • Go 互斥锁和读写互斥锁的实现

    目录 互斥锁 读写互斥锁 先来看这样一段代码,所存在的问题: var wg sync.WaitGroup var x int64 func main() { wg.Add(2) go f() go f() wg.Wait() fmt.Println(x) // 输出:12135 } func f() { for i:=0;i<10000;i++ { x = x+1 } wg.Done() } 这里为什么输出是 12135(不同的机器结果不一样),而不是20000. 因为 x 的赋值,总共分为三个

  • golang并发安全及读写互斥锁的示例分析

    目录 并发安全和锁 互斥锁 读写互斥锁 并发安全和锁 有时候在Go代码中可能会存在多个goroutine同时操作一个资源(临界区),这种情况会发生竞态问题(数据竞态).类比现实生活中的例子有十字路口被各个方向的的汽车竞争:还有火车上的卫生间被车厢里的人竞争. 举个例子: var x int64 var wg sync.WaitGroup func add() { for i := 0; i < 5000; i++ { x = x + 1 } wg.Done() } func main() { w

  • Java多线程之显示锁和内置锁总结详解

    总结多线程之显示锁和内置锁 Java中具有通过Synchronized实现的内置锁,和ReentrantLock实现的显示锁,这两种锁各有各的好处,算是互有补充,这篇文章就是做一个总结. *Synchronized* 内置锁获得锁和释放锁是隐式的,进入synchronized修饰的代码就获得锁,走出相应的代码就释放锁. synchronized(list){ //获得锁 list.append(); list.count(); }//释放锁 通信 与Synchronized配套使用的通信方法通常

  • MySQL锁(表锁,行锁,共享锁,排它锁,间隙锁)使用详解

    锁,在现实生活中是为我们想要隐藏于外界所使用的一种工具.在计算机中,是协调多个进程或县城并发访问某一资源的一种机制.在数据库当中,除了传统的计算资源(CPU.RAM.I/O等等)的争用之外,数据也是一种供许多用户共享访问的资源.如何保证数据并发访问的一致性.有效性,是所有数据库必须解决的一个问题,锁的冲突也是影响数据库并发访问性能的一个重要因素.从这一角度来说,锁对于数据库而言就显得尤为重要. MySQL锁 相对于其他的数据库而言,MySQL的锁机制比较简单,最显著的特点就是不同的存储引擎支持不

  • MySQL中的行级锁、表级锁、页级锁

    在计算机科学中,锁是在执行多线程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互斥要求的满足. 在DBMS中,可以按照锁的粒度把数据库锁分为行级锁(INNODB引擎).表级锁(MYISAM引擎)和页级锁(BDB引擎 ). 一.行级锁 行级锁是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁.行级锁能大大减少数据库操作的冲突.其加锁粒度最小,但加锁的开销也最大.行级锁分为共享锁 和 排他锁. 特点 开销大,加锁慢:会出现死锁:锁定粒度最小,发生锁冲突的概率最低,并发度也

  • Java 死锁解决方案顺序锁和轮询锁

    目录 死锁解决方案分析 解决方案1:顺序锁 解决方案2:轮询锁 总结 前言: 死锁(Dead Lock)指的是两个或两个以上的运算单元(进程.线程或协程),都在等待对方停止执行,以取得系统资源,但是没有一方提前退出,就称为死锁. 死锁示例代码如下: public class DeadLockExample { public static void main(String[] args) { Object lockA = new Object(); // 创建锁 A Object lockB =

  • MySQL的全局锁和表级锁的具体使用

    目录 前言 全局锁 表级锁 表锁 元数据锁(Metadata Locking,简称:MDL锁) 总结 参考资料 前言 在真实的企业开发环境中使用MySQL,MySQL肯定不会只有我一个人使用,而是一个团队显式的使用MySQL,或者是业务隐式的使用MySQL,那么多个用户或者客户端连接使用的时候,我们应该考虑一个问题:如果保证数据并发访问的一致性呢?这一篇我就来聊聊MySQL的锁,不涉及MySQL的事务隔离级别. 全局锁 MySQL的全局锁会关闭所有打开的表,并使全部的表处于只读状态,它们的命令为

  • Mysql锁机制之行锁、表锁、死锁的实现

    目录 一.Mysql锁是什么?锁有哪些类别? 二.行锁和表锁的区别 三.InnoDB死锁概念和死锁案例 死锁场景一之selectforupdate: 死锁场景二之两个update 四.程序开发过程中应该如何注意避免死锁 一.Mysql锁是什么?锁有哪些类别? 锁定义:    同一时间同一资源只能被一个线程访问    在数据库中,除传统的计算资源(如CPU.I/O等)的争用以外,数据也是一种供许多用户共享的资源.如何保证数据并发访问的一致性.有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据

  • iOS中关于音乐锁屏控制音乐(锁屏信息设置)的实例代码

    废话不多说了,直接给大家贴代码了,具体代码如下所示: <pre name="code" class="objc">appDelegate里面加入如下代码获取后台播放权限</pre><pre name="code" class="objc">- (void)setAudioBackstagePlay{ AVAudioSession *audioSession = [AVAudioSession

随机推荐