Go中的锁如何实现

东白随记
0 评论
/ /
0 阅读
/
2435 字
17 2024-09

在Go语言中,锁的实现主要依赖于`sync`包提供的各种同步原语。这些原语包括互斥锁(Mutex)、读写锁(RWMutex)、条件变量(Cond)等,用于在并发编程中保护共享资源,防止数据竞争和不一致的状态。

以下是Go中锁实现的一些关键概念和用法:

1. 互斥锁(Mutex):

`sync.Mutex`是最基本的锁类型,用于保护临界区代码的并发访问。一个互斥锁允许多个goroutine尝试锁定同一资源,但只有一个goroutine能成功锁定并执行临界区代码。其他尝试锁定的goroutine将会被阻塞,直到锁被释放。

```go

import "sync"

var mutex sync.Mutex

func doSomething() {

mutex.Lock() // 加锁

// 临界区代码

mutex.Unlock() // 解锁

}

```

2. 读写锁(RWMutex):

`sync.RWMutex`适用于读多写少的场景。多个goroutine可以同时读取资源,但只允许一个goroutine写入资源。这可以提高并发性能。

```go

import "sync"

var rwmutex sync.RWMutex

var data int // 共享数据

func readSomething() int {

rwmutex.RLock() // 读锁

defer rwmutex.RUnlock() // 读取完成后解锁

return data // 读取数据

}

func updateSomething(newValue int) {

rwmutex.Lock() // 写锁时,会阻塞其他读和写操作

// 更新数据...

rwmutex.Unlock() // 解锁后其他等待的读或写操作可以继续进行

}

```

3. 条件变量(Cond):

`sync.Cond`用于在多个goroutine之间同步等待和通知。它通常与互斥锁一起使用,以保护共享资源的访问。条件变量允许一个或多个goroutine在特定条件未满足时等待,直到其他goroutine发出通知。

```go

import "sync"

var wg sync.WaitGroup // 可选:用于等待goroutine完成工作

var cond = sync.NewCond(&mutex) // 创建条件变量,与互斥锁关联

var sharedValue int // 共享值和条件相关的变量

func waitForCondition() {

wg.Add(1) // 增加WaitGroup计数器,表示等待的goroutine数量增加1个

defer wg.Done() // 当这个goroutine完成工作后减少WaitGroup计数器1个,当减至0时WaitGroup将返回完成信号(即阻塞的其他goroutine会继续执行)

mutex.Lock() // 获取互斥锁(为了访问条件变量和保护临界区)

for !shouldGoOn { // 检查是否满足某个条件,例如一个特定的值是否成立...(通常由外部的某个操作触发)如果不满足就等待下去...循环可以用于提高精度(防止因被打断导致立即结束等待)以减小时间复杂度中的n或任何重复循环带来的n-l部分与自身体积的影响导致更大损失

cond.Wait() // 进入等待状态直到接收到通知并返回运行(在这个过程中如果失去锁的控制,不会退出函数并使流程控制权交还给其他goroutine)...直到满足条件后继续执行...此时需要重新获取互斥锁(如果被其他goroutine释放了)才能继续执行下面的代码...(这确保了条件变量的安全性)...但要注意死锁问题...避免长时间持有互斥锁并在此期间进行复杂的计算...因为这会导致其他goroutine长时间无法获得互斥锁而无法执行...(注意:死锁是并发编程中非常严重的问题)...所以要注意合理设计并发逻辑和释放互斥锁...虽然该方法实现了高度灵活性并且几乎满足了大多数编程场景的要求但依旧有一些应用场景比如业务层过度分散的管理比较棘手不易掌握就非常难以实施也经常难以定位问题的所在并且为了管理这样系统需要做的工作量大成本高;那么请记住还有下面的机制—竞态问题规避;若两个并发线程同改一行值、插入和查询一条数据就会引起并发竞争或脏读等情况——针对该情况我们会引入其它更加细粒度管控的策略去确保竞态发生前的数次协作修改在同一操作组中视为不可分割的一个操作或把读修改写的三个步骤分为一坨任务用分界来阻止发生修改错误/失败时向之前的步长要结果保证协同运算过程的准确和可恢复;使用中间态将之前的流程改为整体以明确可确认事务概念中的单数一个指令保证整个流程的原子性)...但回到主题上,在