如何正确使用 Go 语言中的读写锁

发布时间:2023-05-18

一、读写锁的概念

在并发编程中,读写锁是一种常见的同步机制。读写锁分为两种锁:读锁和写锁。多个 goroutine 可以同时获取读锁,但只能有一个 goroutine 获取写锁,其他 goroutine 等待写锁的释放。 读写锁的实现可以使用 sync 包中的 RWMutex 类型。使用 RWMutex 时,通过调用 RLockRUnlock 方法来获取和释放读锁,调用 LockUnlock 方法来获取和释放写锁。

var rwMutex sync.RWMutex
// 获取读锁
rwMutex.RLock()
// 使用共享资源
// 释放读锁
rwMutex.RUnlock()
// 获取写锁
rwMutex.Lock()
// 使用独占资源
// 释放写锁
rwMutex.Unlock()

二、使用读写锁的场景

通常情况下,读操作的频率远高于写操作。在这种情况下,使用读写锁可以提高并发访问共享资源的效率。

三、写操作实例

下面的代码演示了如何使用 RWMutex 实现线程安全的计数器,计数器可以使用 Get 方法获取当前计数值,使用 Add 方法增加计数值。

type Counter struct {
    value   int
    rwMutex sync.RWMutex
}
func (c *Counter) Get() int {
    c.rwMutex.RLock()
    defer c.rwMutex.RUnlock()
    return c.value
}
func (c *Counter) Add(n int) {
    c.rwMutex.Lock()
    defer c.rwMutex.Unlock()
    c.value += n
}

四、读操作实例

下面的代码演示了如何使用 RWMutex 实现线程安全的缓存,缓存可以使用 Get 方法获取缓存值,使用 Set 方法设置缓存值。

type Cache struct {
    cache   map[string]string
    rwMutex sync.RWMutex
}
func (c *Cache) Get(key string) string {
    c.rwMutex.RLock()
    defer c.rwMutex.RUnlock()
    return c.cache[key]
}
func (c *Cache) Set(key string, value string) {
    c.rwMutex.Lock()
    defer c.rwMutex.Unlock()
    c.cache[key] = value
}

五、读写锁的注意事项

在使用读写锁时,需要注意以下几点:

  1. 当需要更新共享资源时,必须持有写锁才能更新;
  2. 当只需要读取共享资源时,应该持有读锁,以允许多个 goroutine 在同一时间读取资源;
  3. 在使用 RLockRUnlock 获取和释放读锁时,必须保证其成对出现,否则可能会导致死锁;
  4. 在使用 LockUnlock 获取和释放写锁时,必须保证其成对出现,否则可能会导致程序出现异常。