golang mutex锁的竞争关系浅析

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

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

运行结果如下:

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
简要分析:通过运行结果发现所有协程都开始执行,但是进入锁的协程编号变成了3,不是按12345678的顺序获取互斥锁
总结:协程获取锁先后顺序不是按时间来获取,而是竞争关系谁有能力谁上

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

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

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

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

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:读写混合进行

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

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

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

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏极客猴

我爬取豆瓣影评,告诉你《复仇者联盟3》在讲什么?

复联 3 作为漫威 10 年一剑的收官之作。漫威确认下了很多功夫, 给我们奉献一部精彩绝伦的电影。自己也利用周末时间去电影院观看。看完之后,个人觉得无论在打斗特...

10830
来自专栏飞总聊IT

大数据那些事(11):复活的LSM-Tree--BigTable的\b系统实现(修)

修正一些小错误。 BigTable是一个非常复杂的系统,发表的论文面面俱到,但是每个方面都写得并不是很清楚。所幸Google开源了LevelDB这个Key-Va...

40850
来自专栏编程坑太多

requests爬虎牙频道和主播信息

21430
来自专栏生信技能树

TCGA的28篇教程- 使用R语言的RTCGA包获取TCGA数据

前些天被TCGA的终结新闻刷屏,但是一直比较忙,还没来得及仔细研读,但是笔记本躺着的一些TCGA教程快发霉了,借此契机好好整理一下吧,预计二十篇左右的笔记

2.5K30
来自专栏coding

AOC显示器提示OSD锁定怎么办?

macpro虽好,但屏幕实在太小了,而且原生的键盘敲起来很费劲,还是用机械键盘噼里啪啦敲打显得爽快。于是,给macpro外接了键鼠以及27寸的AOC显示器。

2.6K40
来自专栏ml

学编程,学单词.....在学习中积累自己的单词(不断更新__ing)

可以去肆意大话天下,可以去小民一般的言语,但是一定要清楚,知识的积累,至于心中,即便你说这粗俗的话,你的个性,气质依旧在那,比如北大的那啥教师(心中的典范),也...

31250
来自专栏飞总聊IT

大数据那些事(11):复活的LSM-Tree--BigTable的系统实现

BigTable是一个非常复杂的系统,发表的论文写得并不是很清楚。所幸Google开源了LevelDB这个Key-Value Store。这个项目的作者是Jef...

44250
来自专栏养码场

Python小练:爬取豆瓣影评,看一部电影到底在讲什么?

Python的强大,可能在于能做好玩的事情,比如知乎上有关python最火的回答,就是分享怎么用python画出世界名画的赶脚。

13730
来自专栏菩提树下的杨过

js小技巧:tab页切换

依旧只是贴在这里备份,方便以后粘贴复制,高手绕过,以免浪费时间:) <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 T...

43980
来自专栏GopherCoder

『Go 语言学习专栏』-- 第十五期

25440

扫码关注云+社区

领取腾讯云代金券