全局互斥解锁资源竞争 | 学习笔记

简介: 快速学习全局互斥解锁资源竞争

开发者学堂课程【Go 语言核心编程 - 面向对象、文件、单元测试、反射、TCP 编程全局互斥解锁资源竞争】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址:https://developer.aliyun.com/learning/course/626/detail/9752


全局互斥解锁资源竞争

 

内容介绍

一、channel(管道)-看个需求

二、channel(管道)-基本介绍

三、具体代码

 

一、channel(管道)-看个需求

需求:

现在要计算1-200的各个数的阶乘,并且把各个数的阶乘放入到 map 中。最后显示出来。要求使用 goroutine 完成

1、分析思路:

1使用 goroutine 来完成,效率高,但是会出现并发/并行安全问题.

(2)这里就提出了不同 goroutine 如何通信的问题

2、代码实现:

1使用 goroutine 来完成(看看使用 goroutine 并发完成会出现什么题?然后我们会去解决)

2在运行某个程序时,如何知道是否存在资源竞争问题。方法很简单,在编译该程序时,增加一个参数-race 即可

D:\go project\src \go_code\go build-race test.go

D:\goproject\src\go_code >test.exe

Found 2 data race

 

二、channel(管道)-基本介绍:

1、不同 goroutine 之间如何通讯(解决方法)

(1)全局变量加锁同步

(2)使用管道 channel 来解决 

image.png

问题在于:协程1、协程2、协程3、协程4都有可能共同来操纵 map,假设在图示位置有一把锁,当任何一个协程来操纵空间时,先看锁有没有被关闭(lock),如果他是关闭的,就需要进行等待,也就是说对它进行了排队的处理。

image.png

改进:

协程1先持有这把锁,得到这把锁后,继续执行,而后解锁(unlock),当协程1正在操作的时候,协程2先去看锁的情况,发现加锁后,先进行队列缓冲,等待协程1,以此类推,协程3排在协程2后面,进而解决问题。

2、使用全局变量加锁同步改进程序

(1)因为没有对全局变量 m 加锁,因此会出现资源争夺问题,代码会出现错误,提示 concurrent map writes

(2)解决方案:加入互斥锁

3)我们的数的阶乘很大,结果会越界,可以将求阶乘改成 sum += uint64(i)

4)代码改进:

<1> var (

myMap =make(map[int]int, 10)

//声明一个全局的互斥锁

//1ock 是一个全局的互斥锁,

//sync 是包:synchronized 同步

//Mutex:是互斥

lock sync.Mutex

)

<2>// test 函数就是计算 n!,让将这个结果放入到 myMap

func test(n int) {

res :=1

for i :=1;i <=n; i++{

res * = i

}

<3>//这里我们将 res 放入到 myMap

//加锁

lock.Lock()

myMap[n] = res //concurrent map writes?

//解锁

lock.Unlock()

}

编译结果如下:

image.png

改写为:

//主线程休眠10秒,为的是让协程完成任务

//如果没有这句话,主线程很快就退出 m 中还没有结果呢

time .sleep(10*time.Second)

lock.Lock()

for k,v:=range m {

fmt.Printf(“%d!=%v\n”,k,v)

}

lock.Unlock()

编译结果为:

image.png

<4>//这里我们出结果,变量这个结果

lock-Lock()

for iv:-range myMap {

fmt.Printf(“map[%d]=%d\n”,i,v)

}

lock.Unlock()

3 channel(管道)-基本介绍

使用全局变量加锁同步改进程序

但这里有一个间题需要给大家说明

//主线程休眠10秒,为的是让协程完成任务

//如果没有这句话,主线程很快就退出 m 中还没有结果呢

time .sleep(10*time.Second)

lock.Lock()

for k,v:=range m {

fmt.Printf(“%d!=%v\n”,k,v)

}

lock.Unlock()

lock.Lock()lock.Unlock()解释了为什么需要加互斥锁,按理说10秒数上面的协程都应该执行完,后面就不应该出现资源竞争的问题了,但是在实际运行中,还是可能在红框部分出现(运行时增加-race 参数,确实会发现有资源竞争问题),因为我们程序从设计上可以知道10秒就执行完所有协程,但是主线程并不知道,因此底层可能仍然出现资源争夺,因此加入互斥锁即可解决问题

package sync

import "sync"

 

三、具体代码

sync 包提供了基本的同步基元,如互斥锁。除了 Once 和 WaitGroup 类型,大部分都是适用于低水平程序钱程,高水平的同步使用 channel 通信更好一些。

不包括的类型的值不应被拷贝

//需求:现在要计算1-200的各个数的阶乘,并且把各个数的阶乘放入到 map 中.

//最后显示出来。要求使用 goroutine 完成

//思路

//1.编写一个函数,来计算各个数的阶乘,并放入到 map 中.

//2.我们启动的协程多个,统计的将结果放入到 map 中

//3. map 应该做出一个全局的.

var (

myMap = make(map[int]int, 10)

//声明一个全局的互斥锁

// lock 是一个全局的互斥锁,

//sync 是包:synchronized 同步

//Mutex :是互斥

lock sync.Mutex

)

//test 函教就是计算 n!,让将这个结果放入到 myMap func test(n int) {

res :=1

for i :=1;i<= n; i++{

res*=i

}

//这里我们将 res 放入到 myMap

//加锁

lock. Lock()

myMap[n] = res //concurrent map writes?

//解锁

lock. Unlock()

}

func main() {

//我们这里开启多个协程完成这个任务[200个]

for i := 1; i<= 200; i++  {

go test(i)

}

//休眠10秒钟【第二个问题】

time.Sleep(time.Second * 10)

//这里我们输出结果,变量这个结果

lock.Lock()

for i, v := range myMap {

fmt.Printf(“map[%d]=%d\n”, i,v)

}

lock. Unlock()

}

使用全局变量方法加锁时的代码改进:

1. 加入互斥锁

2. goroutine 加锁

3. 读取协程时加锁

Map 存放的是 int 类型,存放的数最大为9223372036854775807

相关文章
|
6月前
|
算法 安全 调度
解决Python并发访问共享资源引起的竞态条件、死锁、饥饿问题的策略
解决Python并发访问共享资源引起的竞态条件、死锁、饥饿问题的策略
92 0
|
Python
互斥访问
Python 中的线程锁是为了在多线程环境下保证对共享资源的互斥访问而设计的。可以使用 Python 的threading模块中的Lock类来创建线程锁。 以下是使用线程锁的一个简单示例:
69 0
|
3月前
|
算法 Java 程序员
同步与互斥(二)
同步与互斥(二)
60 0
|
5月前
|
Java
死锁是线程间争夺资源造成的无限等待现象,Java示例展示了两个线程各自持有资源并等待对方释放,导致死锁。`
【6月更文挑战第20天】死锁是线程间争夺资源造成的无限等待现象,Java示例展示了两个线程各自持有资源并等待对方释放,导致死锁。`volatile`保证变量的可见性和部分原子性,确保多线程环境中值的即时更新。与`synchronized`相比,`volatile`作用于单个变量,不保证原子操作,同步范围有限,但开销较小。`synchronized`提供更全面的内存语义,保证原子性和可见性,适用于复杂并发控制。
41 3
【并发技术03】传统线程互斥技术—synchronized
【并发技术03】传统线程互斥技术—synchronized
|
6月前
|
安全 算法 Linux
Linux多线程【线程互斥与同步】
Linux多线程【线程互斥与同步】
84 0
|
供应链 算法 Linux
Linux系统编程6(线程互斥,锁,同步,生产消费模型)
Linux系统编程6(线程互斥,锁,同步,生产消费模型)
303 2
|
缓存 Oracle 关系型数据库
【数据设计与实现】第5章:同步与互斥
同步与互斥设计原则数据库的一个重要能力就是为多个用户提供并发访问服务,并发度是考察数据库性能的重要指标之一。事务隔离级别定义了并发控制算法的正确性,并让用户通过选择隔离级别在正确性和高性能之间进行平衡。事务重点考虑的是数据层面的并发控制,是属于较上层的同步与互斥。实际上,数据库系统是由大量进程、线程、数据结构构成的,进程、线程会并发地访问、修改数据结构,还需要在较底层级解决数据结构的同步与互斥问题
【数据设计与实现】第5章:同步与互斥
|
Linux
Linux驱动开发——并发和竞态(信号量方式的使用④)
Linux驱动开发——并发和竞态(信号量方式的使用④)
161 0
Linux驱动开发——并发和竞态(信号量方式的使用④)
|
关系型数据库 中间件 MySQL
上手全局锁,死锁
上手全局锁,死锁
上手全局锁,死锁

相关实验场景

更多
下一篇
无影云桌面