go 互斥锁和读写互斥锁

Golang
219
0
0
2024-02-08

互斥锁

互斥锁是一种常用的控制共享资源访问的方法,它能够保证同时只有一个goroutine可以访问共享资源。Go语言中使用sync包的Mutex类型来实现互斥锁。 定义一个锁:

var lock sync.Mutex

加锁:

lock.Lock()

解锁:

lock.Unlock()

完整示例

package main

import (
    "fmt"
    "sync"
)

func main() {
    var lock sync.Mutex
    var wg sync.WaitGroup
    x := 0
    //  开100个goroutine
    for i := 0; i < 100; i++ {
        //  计数
        wg.Add(1)
        go func() {
            //  锁了之后其它goroutine不能对x进行操作
            lock.Lock()
            for j := 0; j < 100; j++ {
                x += 1
            }
            //  解锁
            lock.Unlock()
            //  执行完毕
            wg.Done()
        }()
    }
    //  等待所有goroutine执行完毕
    wg.Wait()
    //  输出x(10000)
    fmt.Println(x)
}

读写互斥锁

互斥锁是完全互斥的,但是有很多实际的场景下是读多写少的,当并发的去读取一个资源不涉及资源修改的时候是没有必要加锁的,这种场景下使用读写锁是更好的一种选择。读写锁在Go语言中使用sync包中的RWMutex类型。 读写锁分为两种:读锁和写锁。当一个goroutine获取读锁之后,其他的goroutine如果是获取读锁会继续获得锁,如果是获取写锁就会等待;当一个goroutine获取写锁之后,其他的goroutine无论是获取读锁还是写锁都会等待。 定义一个读写锁:

var rwlock sync.RWMutex

加写锁:

rwlock.Lock()

解写锁:

rwlock.Unlock()

加读锁:

rwlock.RLock()

解读锁:

rwlock.RUnlock()

完整示例

package main

import (
    "fmt"
    "sync"
)

func main() {
    var rwlock sync.RWMutex
    var wg sync.WaitGroup
    x := 0
    wg.Add(1)
    //  读x
    go func() {
        for a := 0; a < 100; a++ {
            //  读锁
            rwlock.RLock()
            fmt.Println(x)
            //  解读锁
            rwlock.RUnlock()
        }
        wg.Done()
    }()
    //  开100个goroutine写入x
    for i := 0; i < 100; i++ {
        //  计数
        wg.Add(1)
        go func() {
            //  写锁
            rwlock.Lock()
            for j := 0; j < 100; j++ {
                x += 1
            }
            //  解写锁
            rwlock.Unlock()
            //  执行完毕
            wg.Done()
        }()
    }
    //  等待所有goroutine执行完毕
    wg.Wait()
}

运行后可发现每次读操作输出的结果,都相差100,因为写锁在解开前不能进行读操作,因此只有等x加上100后才能读,而读锁在解开前不能进行写操作,因此每次读的时候x不能修改。