在 Go 语言中,有以下几种常用的锁类型:
互斥锁(Mutex)
互斥锁是最常用的一种锁机制,用于保护共享资源在并发访问时的互斥操作。常见的用法如下:
var mutex sync.Mutex
// 通过 Lock() 和 Unlock() 方法保护共享资源的临界区
mutex.Lock()
// 执行对共享资源的操作
mutex.Unlock()
对于 sync.Mutex
,如果在手动调用 Unlock
后,再次在 defer
中调用 Unlock
,会导致 panic。这是因为 sync.Mutex
并没有内部状态来追踪锁的持有者,当重复解锁时,它会引发运行时异常。
下面是一个示例代码,演示了手动解锁后使用 defer
解锁时可能引发的异常:
package main
import (
"sync"
)
func main() {
var mutex sync.Mutex
mutex.Lock()
defer mutex.Unlock() // 在 defer 中尝试解锁
mutex.Unlock() // 手动解锁
// 此处再次调用 mutex.Unlock() 会引发 panic
}
在上述示例中,我们首先手动对互斥锁 mutex
进行解锁操作,然后在 defer
语句中尝试再次解锁。当程序执行到第二次解锁操作时,会引发 sync: unlock of unlocked mutex
的 panic 错误。
因此,在使用互斥锁时,需要确保在 defer
中不会重复解锁已经解锁的互斥锁。一种可靠的做法是只在 defer
中进行解锁操作,并避免在其他地方手动解锁。这样可以确保解锁操作的一致性,并避免不必要的错误。
读写锁(RWMutex)
读写锁允许多个读操作同时进行,但只允许一个写操作进行。常见的用法如下:
var rwLock sync.RWMutex
// 通过 RLock() 和 RUnlock() 方法保护共享资源的读操作
rwLock.RLock()
// 执行对共享资源的读操作
rwLock.RUnlock()
// 通过 Lock() 和 Unlock() 方法保护共享资源的写操作
rwLock.Lock()
// 执行对共享资源的写操作
rwLock.Unlock()
自定义锁sync.Locker
sync.Locker 是 go 标准库 sync 下定义的锁接口:
// A Locker represents an object that can be locked and unlocked.
type Locker interface {
Lock()
Unlock()
}
任何实现了 Lock 和 Unlock 两个方法的类,都可以作为一种锁的实现,最常见的为 go 标准库实现的 sync.Mutex.
条件变量(Cond)
条件变量用于在某个条件满足时进行阻塞和唤醒协程。常见的用法如下:
var cond sync.Cond
// 初始化条件变量
cond = sync.NewCond(&sync.Mutex{})
// 在某个条件不满足时阻塞协程
cond.L.Lock()
for !condition {
cond.Wait()
}
// 执行对共享资源的操作
cond.L.Unlock()
// 满足条件后唤醒等待的协程
cond.Signal()
// 或者唤醒所有等待的协程
cond.Broadcast()
原子操作(Atomic)
原子操作用于在不需要互斥锁的情况下进行原子性的读取和更新操作,常见的用法如下:
var value int32标签:共享资源,浅谈,解锁,sync,value,golang,Unlock,mutex From: https://www.cnblogs.com/peychou/p/17680170.html
// 原子地读取 value 的值
atomic.LoadInt32(&value)
// 原子地更新 value 的值
atomic.StoreInt32(&value, newValue)
// 原子地增加 value 的值
atomic.AddInt32(&value, delta)
// 原子地比较并交换 value 的值
atomic.CompareAndSwapInt32(&value, oldValue, newValue)