GOLANG sync.Mutex和sync.RWMutex

完整教程,请参考如下链接:

点击打开链接

 

 

Package sync

type Mutex

A Mutex is a mutual exclusion lock. Mutexes can be created as part of other structures; the zero value for a Mutex is an unlocked mutex.

A Mutex must not be copied after first use.

type Mutex struct {
    // contains filtered or unexported fields
}
Mutex是最简单的一种锁类型,同时也比较粗暴,当一个goroutine获得了Mutex后,其他goroutine只能乖乖等待这个goroutine释放该Mutex.

func (*Mutex) Lock

func (m *Mutex) Lock()

Lock locks m. If the lock is already in use, the calling goroutine blocks until the mutex is available.


func (*Mutex) Unlock

func (m *Mutex) Unlock()

Unlock unlocks m. It is a run-time error if m is not locked on entry to Unlock.

A locked Mutex is not associated with a particular goroutine. It is allowed for one goroutine to lock a Mutex and then arrange for another goroutine to unlock it.

通过调用Lock()方法对Mutex上锁,通过调用Unlock对Mutex解锁。

e.g. 演示Mutex的简单粗暴:任何时刻,只能有一个goroutine获得该Mutex
package main
 
   
import "fmt"
import "time"
import "sync"
 
   
var mutex sync.Mutex
 
   
func f1(wg *sync.WaitGroup) {
    mutex.Lock()
    fmt.Println("goroutine f1 got mutex")
    for i := 1; i <= 10; i++ {
        fmt.Print(".")
        time.Sleep(1e9)
    }
    fmt.Println("\ngoroutine f1 released mutex")
    mutex.Unlock()
    wg.Done()
}
 
   
func f2(wg *sync.WaitGroup) {
    mutex.Lock()
    fmt.Println("goroutine f2 got mutex")
    for i := 1; i <= 10; i++ {
        fmt.Print(".")
        time.Sleep(1e9)
    }
    fmt.Println("\ngoroutine f2 released mutex")
    mutex.Unlock()
    wg.Done()
}
 
   
func main() {
    var wg sync.WaitGroup
 
   
    wg.Add(2)
 
   
    go f1(&wg)
 
   
    go f2(&wg)
 
   
    wg.Wait()
 
   
    fmt.Println("the main function ended.")
}
 运行: 
  

C:/go/bin/go.exe run test.go [E:/project/go/lx/src]

goroutine f2 got mutex

..........

goroutine f2 released mutex

goroutine f1 got mutex

..........

goroutine f1 released mutex

the main function ended.

成功: 进程退出代码 0.

通过上面的运行结果可以看出,一个goroutine获得了Mutex后,其他goroutine必须等待该goroutine释放了Mutex后,才能获取Mutex。

type RWMutex

An RWMutex is a reader/writer mutual exclusion lock. The lock can be held by an arbitrary number of readers or a single writer. RWMutexes can be created as part of other structures; the zero value for a RWMutex is an unlocked mutex.
An RWMutex must not be copied after first use.

func (*RWMutex) Lock

func (rw *RWMutex) Lock()

Lock locks rw for writing. If the lock is already locked for reading or writing, Lock blocks until the lock is available.

func (*RWMutex) RLock

func (rw *RWMutex) RLock()

RLock locks rw for reading.

func (*RWMutex) RUnlock

func (rw *RWMutex) RUnlock()

RUnlock undoes a single RLock call; it does not affect other simultaneous readers. It is a run-time error if rw is not locked for reading on entry to RUnlock.

func (*RWMutex) Unlock

func (rw *RWMutex) Unlock()

Unlock unlocks rw for writing. It is a run-time error if rw is not locked for writing on entry to Unlock.

As with Mutexes, a locked RWMutex is not associated with a particular goroutine. One goroutine may RLock (Lock) an RWMutex and then arrange for another goroutine to RUnlock (Unlock) it.

RWMutex是一种读写锁,在读锁占用的情况下,会阻止写,但不阻止读,也就是多个goroutine可同时获取读锁;在写锁被占用的情况下,会阻止任何其他的goroutine进来(不论读和写),相当于整个锁由该goroutine独占。

e.g.演示RWMutex可以被上N次读锁

package main
 
   
import "fmt"
import "time"
import "sync"
 
   
var rwmutex sync.RWMutex
 
   
func f1(wg *sync.WaitGroup) {
    rwmutex.RLock()
    fmt.Println("goroutine f1 got read lock")
    for i := 1; i <= 10; i++ {
        fmt.Print("f1")
        time.Sleep(1e9)
    }
    fmt.Println("\ngoroutine f1 released read lock")
    rwmutex.RUnlock()
    wg.Done()
}
 
   
func f2(wg *sync.WaitGroup) {
    rwmutex.RLock()
    fmt.Println("goroutine f2 got read lock")
    for i := 1; i <= 10; i++ {
        fmt.Print("f2")
        time.Sleep(1e9)
    }
    fmt.Println("\ngoroutine f2 released read lock")
    rwmutex.RUnlock()
    wg.Done()
}
 
   
func main() {
    var wg sync.WaitGroup
 
   
    wg.Add(2)
 
   
    go f1(&wg)
 
   
    go f2(&wg)
 
   
    wg.Wait()
 
   
    fmt.Println("the main function ended")
}
 运行: 
  

C:/go/bin/go.exe run test2.go [E:/project/go/lx/src]

goroutine f2 got read lock

goroutine f1 got read lock

f1f2f1f2f1f2f2f1f1f2f2f1f1f2f2f1f1f2f2f1

goroutine f1 released read lock

goroutine f2 released read lock

the main function ended

成功: 进程退出代码 0.

e.g.演示RWMutex读锁和写锁相互排斥(本例先上写锁)

package main
 
   
import (
    "fmt"
    "sync"
    "time"
)
 
   
var rwmutex sync.RWMutex
 
   
func f1(wg *sync.WaitGroup) {
    rwmutex.RLock()
    fmt.Println("The goroutine f1 had got the read lock")
    fmt.Print("f1:")
    for i := 1; i <= 10; i++ {
        fmt.Print(".")
        time.Sleep(1e9)
    }
    fmt.Println("\nThe goroutine f1 had released the read lock")
    rwmutex.RUnlock()
    wg.Done()
}
 
   
func main() {
    var wg sync.WaitGroup
 
   
    wg.Add(1)
 
   
    rwmutex.Lock()
    fmt.Println("The main goroutine had got the write lock")
    go f1(&wg)
    fmt.Print("main:")
    for i := 1; i <= 10; i++ {
        fmt.Print(".")
        time.Sleep(1e9)
    }
 
   
    fmt.Println("\nThe main goroutine had released the write lock")
    rwmutex.Unlock()
 
   
    wg.Wait()
 
   
    fmt.Println("The main function ended.")
}
 
   

运行:

C:/go/bin/go.exe run test.go [E:/project/go/test/src]

The main goroutine had got the write lock

main:..........

The main goroutine had released the write lock

The goroutine f1 had got the read lock

f1:..........

The goroutine f1 had released the read lock

The main function ended.

成功: 进程退出代码 0.

从运行结果可以看出,其中一个goroutine获得了写锁后,其他goroutine必须等待相应的写锁被释放后,才能获得读锁。

e.g.演示RWMutex读锁和写锁相互排斥(本例先上读锁)

package main
 
   
import (
    "fmt"
    "sync"
    "time"
)
 
   
var rwmutex sync.RWMutex
 
   
func f1(wg *sync.WaitGroup) {
    rwmutex.Lock()
    fmt.Println("The goroutine f1 had got the write lock")
    fmt.Print("f1:")
    for i := 1; i <= 10; i++ {
        fmt.Print(".")
        time.Sleep(1e9)
    }
    fmt.Println("\nThe goroutine f1 had released the write lock")
    rwmutex.Unlock()
    wg.Done()
}
 
   
func main() {
    var wg sync.WaitGroup
 
   
    wg.Add(1)
 
   
    rwmutex.RLock()
    fmt.Println("The main goroutine had got the read lock")
    go f1(&wg)
    fmt.Print("main:")
    for i := 1; i <= 10; i++ {
        fmt.Print(".")
        time.Sleep(1e9)
    }
 
   
    fmt.Println("\nThe main goroutine had released the read lock")
    rwmutex.RUnlock()
 
   
    wg.Wait()
 
   
    fmt.Println("The main function ended.")
}
 
   

运行:

C:/go/bin/go.exe run test.go [E:/project/go/test/src]

The main goroutine had got the read lock

main:..........

The main goroutine had released the read lock

The goroutine f1 had got the write lock

f1:..........

The goroutine f1 had released the write lock

The main function ended.

成功: 进程退出代码 0.


从上面的两个例子可以看出,RWMutex是支持读锁和写锁的,不向Mutex那么简单粗暴,但是RWMutex的读锁和写锁是互斥的,也就是读锁和写锁不能同时存在;但是RWMutex是可以同时支持多个读锁的;任何时刻,RWMutex只能有一个写锁。

你可能感兴趣的:(go)