Go学习笔记 -- 互斥锁

在之前我们通过 sync.Mutex 实现了多个协程有顺序的执行,在这里再次深入了解一下 sync.Mutex 。

作用

sync.Mutex 用于保证同时只有一个 Goroutine 能接触到变量或代码块,避免多个协程之间产生冲突。

如何使用

如下代码,确保多个协程在同一时刻只有一个协程能够对 protecting 执行加一操作。否则最后的计算结果将无法控制。

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

var mu sync.Mutex
var protecting uint

func do() {
	mu.Lock()
	protecting = protecting + 1
	mu.Unlock()
}

func main() {
	count := 1000
	for i := 0; i < count; i++ {
		go do()
	}
	time.Sleep(3000)
	fmt.Printf("this value is %d", protecting)
}

注意事项

要随机解锁互斥锁,必要时使用defer语句

如上代码 我们可以将代码修改为:

func do() {
	mu.Lock()
	defer mu.Unlock()
	protecting = protecting + 1
}

在锁定之后马上定义 defer 函数,不管后续代码是否出现异常(非运行时恐慌),都会将锁解锁。

不要对尚未锁定或者已解锁的互斥锁解锁

对尚未锁定或者已解锁的互斥锁解锁会抛出运行时恐慌 panic,这种情况下 defer 函数是无法恢复的,程序会直接崩溃

不要在函数之间直接传递互斥锁

原因是,互斥锁的基本类型实际上是结构体,这就表明在函数中传递时是属于值传递的,实际上是传递的它的副本。
如下代码:

func do(mu sync.Mutex) {
	mu.Unlock()
	fmt.Printf("unlocked in func do")
}
func main() {
	var mu sync.Mutex
	mu.Lock()
	do(mu)

	//再次尝试加锁
	mu.Lock()
	fmt.Printf("relock success")
}

运行后会爆出 panic ,提示如下信息

unlocked in func do
fatal error: all goroutines are asleep - deadlock!

原因就是 mu 的锁实际上还没有解锁,我们在方法中解锁的之不是他的一个副本,然而我们之后又在方法中进行了第二次加锁,导致死锁。
对此我们在传递互斥锁的时候,要传递它的指针:

func do(mu *sync.Mutex) {
	mu.Unlock()
	fmt.Printf("unlocked in func do\n")
}

func main() {
	var mu sync.Mutex
	mu.Lock()
	do(&mu)

	//再次尝试加锁
	mu.Lock()
	fmt.Printf("relock success\n")
}
-----------------------------
unlocked in func do
relock success

sync.RWMutex

sync.RWMutex 是读/写互斥锁,其获取锁的逻辑是:

  • 当有协程获取到 RWMutex 的写锁时,其他协程无法获取 RWMutex 的读锁和写锁
  • 当有些成获取到 RWMutex 的读锁时,其他协程无法获取 RWMutex 的写锁,但是可以获取到读锁

总结来说就是,RWMutex 的写操作之间互斥,写操作和读操作之间也是互斥的。
当写锁被解锁时,会唤醒所有等待读锁的协程,正常情况下所有等待读锁的协程都将获取到读锁。
当读锁被解锁时,如果没有任何协程持有读锁,那么会唤醒所有等待写锁的协程,并最终只会有一个(等待时间最长的)协程获取到写锁的锁定。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mingvvv

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值