Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >golang mutex锁的竞争关系浅析

golang mutex锁的竞争关系浅析

作者头像
地球流浪猫
发布于 2018-08-02 07:26:16
发布于 2018-08-02 07:26:16
72600
代码可运行
举报
文章被收录于专栏:流浪猫的golang流浪猫的golang
运行总次数:0
代码可运行

刚才对golang的锁关系进行 一番思索,想着协程获取golang 对象锁的,是按先按时间先后顺序获取的,其实不然。下面请看代码,顺带写了2种读写锁的应用。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (
	"sync"
	"fmt"
	"time"
)
//开启10个线程  同时去竞争一个互斥锁 谁有能力谁上

var mutex *sync.Mutex;
var  ch chan int


func main() {
	mutex=new(sync.Mutex)
	fmt.Println("start")
	ch=make(chan int )
	for i:=0; i<10; i++ {
		go TestMutex(ch,i)
	}
	for i:=0; i<10; i++ {
	<-ch
	}
}

func TestMutex(ch chan int,index int)  {
	fmt.Println("to enter mutex","index=",index)
	mutex.Lock();
	defer mutex.Unlock()
	defer fmt.Println("unLock","index=",index)
	fmt.Println("in mutex","index=",index)
	time.Sleep(2*time.Second)
	ch<-1

运行结果如下:

代码语言:javascript
代码运行次数:0
运行
复制
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
start
to enter mutex index= 3
to enter mutex index= 9
in mutex index= 3
to enter mutex index= 5
to enter mutex index= 6
to enter mutex index= 7
to enter mutex index= 8
to enter mutex index= 1
to enter mutex index= 0
to enter mutex index= 4
to enter mutex index= 2
unLock index= 3
in mutex index= 9
unLock index= 9
in mutex index= 5
unLock index= 5
in mutex index= 6
unLock index= 6
in mutex index= 7
unLock index= 7
in mutex index= 8
unLock index= 8
in mutex index= 1
unLock index= 1
in mutex index= 0
unLock index= 0
in mutex index= 4
in mutex index= 2
unLock index= 4
unLock index= 2
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
简要分析:通过运行结果发现所有协程都开始执行,但是进入锁的协程编号变成了3,不是按12345678的顺序获取互斥锁
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
总结:协程获取锁先后顺序不是按时间来获取,而是竞争关系谁有能力谁上

读写锁(RWmutex)的模型一: 多个协程一起读

代码语言:javascript
代码运行次数:0
运行
复制
代码语言:javascript
代码运行次数:0
运行
复制
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var RWmutex *sync.RWMutex;
var  RWch chan int

func main() {
   RWmutex=new(sync.RWMutex)
   fmt.Println("start")
   RWch=make(chan int )
   for i:=0; i<10; i++ {
      go TestRWMutex(i)
   }
   for i:=0; i<10; i++ {
      <-RWch
   }
}

func TestRWMutex(index int)  {
   fmt.Println("进入读写锁,准备读点东西","index=",index)
   RWmutex.RLock();
   //读取数据
   fmt.Println("读点东西..","index=",index)
   time.Sleep(4*time.Second)
   RWmutex.RUnlock()
   fmt.Println("离开读写锁..","index=",index)
   RWch<-1
}

运行结果:start start 进入读写锁,准备读点东西 index= 0 进入读写锁,准备读点东西 index= 2 读点东西.. index= 2 进入读写锁,准备读点东西 index= 4 读点东西.. index= 4 进入读写锁,准备读点东西 index= 9 读点东西.. index= 9 进入读写锁,准备读点东西 index= 3 读点东西.. index= 3 进入读写锁,准备读点东西 index= 8 读点东西.. index= 8 读点东西.. index= 0 进入读写锁,准备读点东西 index= 1 读点东西.. index= 1 进入读写锁,准备读点东西 index= 7 读点东西.. index= 7 进入读写锁,准备读点东西 index= 6 读点东西.. index= 6 进入读写锁,准备读点东西 index= 5 读点东西.. index= 5 离开读写锁.. index= 4 离开读写锁.. index= 3 离开读写锁.. index= 9 离开读写锁.. index= 2 离开读写锁.. index= 7 离开读写锁.. index= 1 离开读写锁.. index= 5 离开读写锁.. index= 0 离开读写锁.. index= 6

离开读写锁.. index= 8

简要分析:读锁可连续加上。

读写锁模型 写入得时候保护,只有一个协程能写其他的协程不能写

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (
	"fmt"
	"time"
	"sync"
)
var RWWmutex *sync.RWMutex;
var  RWWch chan int
// 读写模型2, 写的时候什么也做不了,
//也就是写保护
func main() {
	RWWmutex=new(sync.RWMutex)
	fmt.Println("start")
	RWWch=make(chan int )
	for i:=0; i<10; i++ {
		go TestRWWMutex(RWWch,i)
	}
	for i:=0; i<10; i++ {
		<-RWWch
	}
}

func TestRWWMutex(ch chan int,index int) {
	fmt.Println("进入写锁","index=",index)
	RWWmutex.Lock();

	//写东西..
	fmt.Println("正字写东西.....","index=",index)
	time.Sleep(1*time.Second)
	RWWmutex.Unlock()
	fmt.Println("离开写锁","index=",index)
	RWWch<-1
}

运行结果:

start 进入写锁 index= 0 进入写锁 index= 1 进入写锁 index= 6 进入写锁 index= 7 进入写锁 index= 2 进入写锁 index= 3 进入写锁 index= 9 正字写东西..... index= 0 进入写锁 index= 4 进入写锁 index= 5 进入写锁 index= 8 离开写锁 index= 0 正字写东西..... index= 1 正字写东西..... index= 6 离开写锁 index= 1 正字写东西..... index= 7 离开写锁 index= 6 离开写锁 index= 7 正字写东西..... index= 2 离开写锁 index= 2 正字写东西..... index= 3 离开写锁 index= 3 正字写东西..... index= 9 离开写锁 index= 9 正字写东西..... index= 4 离开写锁 index= 4 正字写东西..... index= 5 离开写锁 index= 5 正字写东西..... index= 8

离开写锁 index= 8

不难看出 写东西的时候受到了锁的保护

模型4:读写混合进行

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

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

//读写同时发生的模型
//读的时候的写 NO
//写的时候读 NO


var WR_Wmutex *sync.RWMutex;
//var WR_Rmutex *sync.RWMutex;
var  WRch chan int

func main() {
	WR_Wmutex=new(sync.RWMutex)
	fmt.Println("start")
	WRch=make(chan  int )

	for i:=0;i<5;i++  {
		go TestRW_WMutex(i)
		go TestRW_RMutex(i)
	}
	for i:=0;i<10 ; i++ {
		<-WRch
	}
}

func TestRW_WMutex(index int) {
	WR_Wmutex.Lock();
	//写东西..
	fmt.Println("BBB 测试写,正在写东西.....","index=",index)
	time.Sleep(1*time.Second)
	fmt.Println("BBB 测试写,即将离开写锁","index=",index)
	WR_Wmutex.Unlock()

	WRch<-1
}

func TestRW_RMutex(index int) {
	WR_Wmutex.RLock();
	//写东西..
	fmt.Println("AAA 测试读,正在读东西.....","index=",index)
	time.Sleep(1*time.Second)
	fmt.Println("AAA 测试读,即将离开读锁","index=",index)
	WR_Wmutex.RUnlock()

	WRch<-1
}

运行结果:

2018-03-12 11:21:59 BBB 测试写,正在写东西..... index= 0 2018-03-12 11:22:00 BBB 测试写,即将离开写锁 index= 0 2018-03-12 11:22:00 AAA 测试读,正在读东西..... index= 4 2018-03-12 11:22:00 AAA 测试读,正在读东西..... index= 2 2018-03-12 11:22:00 AAA 测试读,正在读东西..... index= 3 2018-03-12 11:22:00 AAA 测试读,正在读东西..... index= 0 2018-03-12 11:22:00 AAA 测试读,正在读东西..... index= 1 2018-03-12 11:22:01 AAA 测试读,即将离开读锁 index= 4 2018-03-12 11:22:01 AAA 测试读,即将离开读锁 index= 2 2018-03-12 11:22:01 AAA 测试读,即将离开读锁 index= 1 2018-03-12 11:22:01 AAA 测试读,即将离开读锁 index= 3 2018-03-12 11:22:01 AAA 测试读,即将离开读锁 index= 0 2018-03-12 11:22:01 BBB 测试写,正在写东西..... index= 1 2018-03-12 11:22:02 BBB 测试写,即将离开写锁 index= 1 2018-03-12 11:22:02 BBB 测试写,正在写东西..... index= 2 2018-03-12 11:22:03 BBB 测试写,即将离开写锁 index= 2 2018-03-12 11:22:03 BBB 测试写,正在写东西..... index= 3 2018-03-12 11:22:04 BBB 测试写,即将离开写锁 index= 3 2018-03-12 11:22:04 BBB 测试写,正在写东西..... index= 4

2018-03-12 11:22:05 BBB 测试写,即将离开写锁 index= 4

改变一下读写锁加入的顺序,先加读锁,后加写锁.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func main() {
	WR_Wmutex=new(sync.RWMutex)
	fmt.Println("start")
	WRch=make(chan  int )

	for i:=0;i<5;i++  {
		go TestRW_RMutex(i)
		go TestRW_WMutex(i)
	}
	for i:=0;i<10 ; i++ {
		<-WRch
	}
}

运行结果:

2018-03-12 11:18:19 AAA 测试读,正在读东西..... index= 0 2018-03-12 11:18:20 AAA 测试读,即将离开读锁 index= 0 2018-03-12 11:18:20 BBB 测试写,正在写东西..... index= 4 2018-03-12 11:18:21 BBB 测试写,即将离开写锁 index= 4 2018-03-12 11:18:21 AAA 测试读,正在读东西..... index= 4 2018-03-12 11:18:21 AAA 测试读,正在读东西..... index= 1 2018-03-12 11:18:21 AAA 测试读,正在读东西..... index= 2 2018-03-12 11:18:21 AAA 测试读,正在读东西..... index= 3 2018-03-12 11:18:22 AAA 测试读,即将离开读锁 index= 3 2018-03-12 11:18:22 AAA 测试读,即将离开读锁 index= 2 2018-03-12 11:18:22 AAA 测试读,即将离开读锁 index= 4 2018-03-12 11:18:22 AAA 测试读,即将离开读锁 index= 1 2018-03-12 11:18:22 BBB 测试写,正在写东西..... index= 0 2018-03-12 11:18:23 BBB 测试写,即将离开写锁 index= 0 2018-03-12 11:18:23 BBB 测试写,正在写东西..... index= 1 2018-03-12 11:18:24 BBB 测试写,即将离开写锁 index= 1 2018-03-12 11:18:24 BBB 测试写,正在写东西..... index= 2 2018-03-12 11:18:25 BBB 测试写,即将离开写锁 index= 2 2018-03-12 11:18:25 BBB 测试写,正在写东西..... index= 3 2018-03-12 11:18:26 BBB 测试写,即将离开写锁 index= 3

运行结果分析:读的时候不能写,可以多次读;写的时候不能读,也不能写。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018年03月09日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Golang同步:锁的使用案例详解
互斥锁 互斥锁是传统的并发程序对共享资源进行访问控制的主要手段。它由标准库代码包sync中的Mutex结构体类型代表。只有两个公开方法 Lock Unlock 类型sync.Mutex的零值表示了未被锁定的互斥量。 <code class="language-golang" hljs="">var mutex sync.Mutex mutex.Lock()</code> 复制代码 示例 <code class="language-golang" hljs="">// test for Go // //
李海彬
2018/03/23
6960
GO语言并发编程之互斥锁、读写锁详解
在本节,我们对Go语言所提供的与锁有关的API进行说明。这包括了互斥锁和读写锁。我们在第6章描述过互斥锁,但却没有提到过读写锁。这两种锁对于传统的并发程序来说都是非常常用和重要的。 一、互斥锁 互斥锁是传统的并发程序对共享资源进行访问控制的主要手段。它由标准库代码包sync中的Mutex结构体类型代表。sync.Mutex类型(确切地说,是*sync.Mutex类型)只有两个公开方法——Lock和Unlock。顾名思义,前者被用于锁定当前的互斥量,而后者则被用来对当前的互斥量进行解锁。 类型sync.Mut
李海彬
2018/03/19
8300
Golang包——sync
1.它允许任意读操作同时进行 2.同一时刻,只允许有一个写操作进行 3.并且一个写操作被进行过程中,读操作的进行也是不被允许的 4.读写锁控制下的多个写操作之间都是互斥的 5.写操作与读操作之间也都是互斥的 6.多个读操作之间却不存在互斥关系 写操作的锁定和解锁
羊羽shine
2019/05/29
1K0
Golang并发的次优选择:sync包
我们都知道Golang并发优选channel,但channel不是万能的,Golang为我们提供了另一种选择:sync。通过这篇文章,你会了解sync包最基础、最常用的方法,至于sync和channel之争留给下一篇文章。
大彬
2019/04/11
6480
Golang sync.Mutex 与 sync.RWMutex
Golang中sync包实现了两种锁,Mutex(互斥锁)和RWMutex(读写锁),其中RWMutex是基于Mutex实现的。
恋喵大鲤鱼
2019/06/14
1.9K0
锁的使用场景主要涉及到哪些?读写锁为什么会比普通锁快【Golang 入门系列十六】
前面已经讲过很多Golang系列知识,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.html,
章为忠学架构
2019/12/15
2.4K0
Golang深入浅出之-互斥锁(sync.Mutex)与读写锁(sync.RWMutex)
在Go语言的并发编程中,互斥锁(sync.Mutex)与读写锁(sync.RWMutex)是实现线程安全、保护共享资源免受竞态条件影响的核心工具。本文将深入浅出地解析这两种锁的特性和用法,探讨常见问题、易错点及应对策略,并通过代码示例加深理解。
Jimaks
2024/04/26
2.5K0
golang的锁
在Go语言中,锁用于同步访问共享资源。Go语言提供了两种类型的锁:互斥锁(mutex)和读写锁(RWMutex)。
运维开发王义杰
2023/08/21
2510
golang的锁
golang之包和锁的机制
互斥锁 同一时刻只有一个携程在操作 package main import ( "fmt" "math/rand" "sync" "time" ) //互斥锁 var lock sync.Mutex func testMap() { var a map[int]int a = make(map[int]int, 5) a[8] = 10 a[3] = 10 a[2] = 10 a[1] = 10 for i := 0
超蛋lhy
2018/08/31
3240
面试官:说说RWMutex与Mutex的区别
RWMutex 对读锁不排斥,对写锁排斥,同一时刻只能有一个写锁持有但允许多个多读锁持有,因为多个读者并不会改变共享数据,但存在写者时数据会被改变,此时读者阻塞。
小锟哥哥
2022/05/10
5610
面试官:说说RWMutex与Mutex的区别
go 互斥锁和读写互斥锁
互斥锁是一种常用的控制共享资源访问的方法,它能够保证同时只有一个goroutine可以访问共享资源。Go语言中使用sync包的Mutex类型来实现互斥锁。 定义一个锁:
TomatoCool
2023/09/14
3430
Golang中互斥锁和读写互斥锁
        在Golang中,互斥锁(Mutex)是一种基本的同步原语,用于实现对共享资源的互斥访问。互斥锁通过在代码中标记临界区来控制对共享资源的访问,从而保证同一时间只有一个 goroutine 可以访问共享资源,避免了并发访问时的数据竞争和不一致性问题。
周小末天天开心
2023/10/16
4370
互斥锁与读写锁:如何使用锁完成Go程同步?
这张图容易让人产生误解,容易让人误以为goroutine1获取的锁,只有goroutine1能释放,其实不是这样的。“秦失其鹿,天下共逐之”。在这张图中,goroutine1与goroutine2竞争的是一种互斥锁。goroutine1成功获取锁以后,锁变成锁定状态,此时goroutine2也可以解锁。
LIYI
2021/01/26
1.1K0
Golang异步编程方式和技巧
Golang基于多线程、协程实现,与生俱来适合异步编程,当我们遇到那种需要批量处理且耗时的操作时,传统的线性执行就显得吃力,这时就会想到异步并行处理。下面介绍一些异步编程方式和技巧。
用户2132290
2024/04/12
1.5K0
Golang异步编程方式和技巧
GO 语言处理并发的时候我们是选择sync还是channel
以前写 C 的时候,我们一般是都通过共享内存来通信,对于并发去操作某一块数据时,为了保证数据安全,控制线程间同步,我们们会去使用互斥锁,加锁解锁来进行处理
阿兵云原生
2023/10/24
2710
GO 语言处理并发的时候我们是选择sync还是channel
使goroutine同步的方法总结
在前面并发性能对比的文章中,我们可以看到Golang处理大并发的能力十分强劲,而且开发也特别方便,只需要用go关键字即可开启一个新的协程。
李海彬
2018/10/24
1.5K0
使goroutine同步的方法总结
17.Go语言-线程同步
在 Go 语言中,经常会遇到并发的问题,当然我们会优先考虑使用通道,同时 Go 语言也给出了传统的解决方式 Mutex(互斥锁) 和 RWMutex(读写锁) 来处理竞争条件。
面向加薪学习
2022/09/04
3070
Go基础之锁的初识
当我们的程序就一个线程的时候是不需要用到锁的,但是通常我们实际的代码不会是单个线程的,所有这个时候就需要用到锁了,那么关于锁的使用场景主要涉及到哪些呢? 当我们多个线程在读相同的数据的时候则是需要加锁的 当我们的程序既有读又有写的时候更是需要加锁的 当我们有多个线程在写的时候同样也是需要加锁 互斥锁 互斥锁:同一个时刻只有一个线程能够拿到锁 我们先通过一个例子来演示,如果当多个线程同时更改一个变量,结果会是怎么样 不加锁版本 package main import ( "sync" "fm
coders
2018/03/30
5480
Golang 基础:底层并发原语 Mutex RWMutex Cond WaitGroup Once等使用和基本实现
上一篇 《原生并发 goroutine channel 和 select 常见使用场景》 介绍了基于 CSP 模型的并发方式。
张拭心 shixinzhang
2022/05/10
4520
Golang 基础:底层并发原语 Mutex RWMutex Cond WaitGroup Once等使用和基本实现
Go 专栏|并发编程:goroutine,channel 和 sync
原文链接: Go 专栏|并发编程:goroutine,channel 和 sync
AlwaysBeta
2021/09/16
7000
Go 专栏|并发编程:goroutine,channel 和 sync
相关推荐
Golang同步:锁的使用案例详解
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档