Golang 互斥锁与读写锁

Rnben · · 806 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

互斥锁

代码示例

package main

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

func main() {
    //声明
    var mutex sync.Mutex
    fmt.Println("Lock the lock. (G0)")
    //加锁mutex
    mutex.Lock()

    fmt.Println("The lock is locked.(G0)")
    for i := 1; i < 4; i++ {
        go func(i int) {
            fmt.Printf("----Lock the lock. (G%d)\n", i)
            mutex.Lock()
            fmt.Printf("++++The lock is locked. (G%d)\n", i)
        }(i)
    }
    //休息一会,等待打印结果
    time.Sleep(time.Second)
    fmt.Println("Unlock the lock. (G0)")
    //解锁mutex
    mutex.Unlock()

    fmt.Println("The lock is unlocked. (G0)")
    //休息一会,等待打印结果
    time.Sleep(time.Second)
    Lock the lock. (G0)
    // 同一个互斥锁的成对锁定和解锁操作放在同一层次的代码块中。
}

打印结果

Lock the lock. (G0)
The lock is locked.(G0)
----Lock the lock. (G2)
----Lock the lock. (G1)
----Lock the lock. (G3)
Unlock the lock. (G0)
The lock is unlocked. (G0)
++++The lock is locked. (G2) //随机 G1 G2 G3

使用互斥锁的注意事项如下:

  1. 不要重复锁定互斥锁;
    对一个已经被锁定的互斥锁进行锁定,是会立即阻塞当前的 goroutine 的。这个 goroutine 所执行的流程,会一直停滞在调用该互斥锁的Lock方法的那行代码上。
  2. 不要忘记解锁互斥锁,必要时使用defer语句;
    应该保证,对于每一个锁定操作,都要有且只有一个对应的解锁操作,避免重复锁定
  3. 不要对尚未锁定或者已解锁的互斥锁解锁;
    解锁未锁定的互斥锁会立即引发 panic,这种由 Go 语言运行时系统自行抛出的 panic 都属于致命错误,都是无法被恢复的。
  4. 不要在多个函数之间直接传递互斥锁。
    sync.Mutex是一个结构体类型,属于值类型中的一种。把它传给一个函数、将它从函数中返回、把它赋给其他变量、让它进入某个通道都会导致它的副本的产生。原值和它的副本,以及多个副本之间都是完全独立的,它们都是不同的互斥锁。

建议:尽量避免把一个互斥锁同时用在了多个地方,多个goroutine 争用这把锁增大死锁可能性。而最简单、有效的方式就是让每一个互斥锁都只保护一个临界区或一组相关临界区。

读写锁

读写锁sync.RWMutex是把对共享资源的“读操作”和“写操作”区别对待了。它可以对这两种操作施加不同程度的保护。换句话说,相比于互斥锁,读写锁可以实现更加细腻的访问控制。
对于某个受到读写锁保护的共享资源,多个写操作不能同时进行,写操作和读操作也不能同时进行,但多个读操作却可以同时进行。


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:Rnben

查看原文:Golang 互斥锁与读写锁

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

806 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传