Golang 中的 RLock() 和 Lock() 有什么区别?
what is the difference between RLock() and Lock() in Golang?
Golang 中的 RLock() 和 Lock() 有什么区别,我们在使用互斥锁时如何有效地使用它们?
RWMutex 是 reader/writer 互斥锁。锁可以由任意数量的读者或单个作者持有。 RWMutex 的零值是未锁定的互斥量。
RWMutex 不能在第一次使用后复制。
如果一个 goroutine 持有一个 RWMutex 用于读取,而另一个 goroutine 可能调用 Lock,则在释放初始读锁之前,任何 goroutine 都不应期望能够获取读锁。特别是,这禁止递归读取锁定。这是为了确保锁最终可用;阻塞的 Lock 调用将新读者排除在获取锁之外。
Mutex 是一种互斥锁。 Mutex 的零值是未锁定的互斥量。
golang 提供通道是并发控制的最佳实践,所以我认为使用 sync.lock 的有效方式没有使用它,而是使用通道。
Lock(): 一次只有一个go例程read/write通过获取锁
RLock(): 多个go routine可以通过获取锁一次读取(不能写入)
package main
import (
"fmt"
"sync"
"time"
)
func main() {
a := 0
lock := sync.RWMutex{}
for i := 1; i < 10; i++ {
go func(i int) {
lock.Lock()
fmt.Printf("Lock: from go routine %d: a = %d\n",i, a)
time.Sleep(time.Second)
lock.Unlock()
}(i)
}
b := 0
for i := 11; i < 20; i++ {
go func(i int) {
lock.RLock()
fmt.Printf("RLock: from go routine %d: b = %d\n",i, b)
time.Sleep(time.Second)
lock.RUnlock()
}(i)
}
<-time.After(time.Second*10)
}
1) 当一个go-routine已经获取了一个RLock()时,另一个go-routine是否可以获取一个Lock()用于写入或者它必须等到RUnlock()发生?
- 要获取用于写入的 Lock(),它必须等到 RUnlock()
2) 当有人已经为 map 获取了 Lock() 时会发生什么,其他 go-routine 是否仍然可以获取 RLock()
- 如果某人 X 已经获取了 Lock(),那么其他获取 RLock() 的 go-routine 将不得不等到 X 释放锁(Unlock())
3)假设我们这里处理的是Maps,有没有可能出现"concurrent read/write of Map"错误?
- 地图不是线程安全的。所以 "concurrent read/write of Map" 会导致错误。
有关更多说明,请参见以下示例:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
lock := sync.RWMutex{}
b := map[string]int{}
b["0"] = 0
go func(i int) {
lock.RLock()
fmt.Printf("RLock: from go routine %d: b = %d\n",i, b["0"])
time.Sleep(time.Second*3)
fmt.Printf("RLock: from go routine %d: lock released\n",i)
lock.RUnlock()
}(1)
go func(i int) {
lock.Lock()
b["2"] = i
fmt.Printf("Lock: from go routine %d: b = %d\n",i, b["2"])
time.Sleep(time.Second*3)
fmt.Printf("Lock: from go routine %d: lock released\n",i)
lock.Unlock()
}(2)
<-time.After(time.Second*8)
fmt.Println("*************************************8")
go func(i int) {
lock.Lock()
b["3"] = i
fmt.Printf("Lock: from go routine %d: b = %d\n",i, b["3"])
time.Sleep(time.Second*3)
fmt.Printf("Lock: from go routine %d: lock released\n",i)
lock.Unlock()
}(3)
go func(i int) {
lock.RLock()
fmt.Printf("RLock: from go routine %d: b = %d\n",i, b["3"])
time.Sleep(time.Second*3)
fmt.Printf("RLock: from go routine %d: lock released\n",i)
lock.RUnlock()
}(4)
<-time.After(time.Second*8)
}
Golang 中的 RLock() 和 Lock() 有什么区别,我们在使用互斥锁时如何有效地使用它们?
RWMutex 是 reader/writer 互斥锁。锁可以由任意数量的读者或单个作者持有。 RWMutex 的零值是未锁定的互斥量。
RWMutex 不能在第一次使用后复制。
如果一个 goroutine 持有一个 RWMutex 用于读取,而另一个 goroutine 可能调用 Lock,则在释放初始读锁之前,任何 goroutine 都不应期望能够获取读锁。特别是,这禁止递归读取锁定。这是为了确保锁最终可用;阻塞的 Lock 调用将新读者排除在获取锁之外。
Mutex 是一种互斥锁。 Mutex 的零值是未锁定的互斥量。
golang 提供通道是并发控制的最佳实践,所以我认为使用 sync.lock 的有效方式没有使用它,而是使用通道。
Lock(): 一次只有一个go例程read/write通过获取锁
RLock(): 多个go routine可以通过获取锁一次读取(不能写入)
package main
import (
"fmt"
"sync"
"time"
)
func main() {
a := 0
lock := sync.RWMutex{}
for i := 1; i < 10; i++ {
go func(i int) {
lock.Lock()
fmt.Printf("Lock: from go routine %d: a = %d\n",i, a)
time.Sleep(time.Second)
lock.Unlock()
}(i)
}
b := 0
for i := 11; i < 20; i++ {
go func(i int) {
lock.RLock()
fmt.Printf("RLock: from go routine %d: b = %d\n",i, b)
time.Sleep(time.Second)
lock.RUnlock()
}(i)
}
<-time.After(time.Second*10)
}
1) 当一个go-routine已经获取了一个RLock()时,另一个go-routine是否可以获取一个Lock()用于写入或者它必须等到RUnlock()发生?
- 要获取用于写入的 Lock(),它必须等到 RUnlock()
2) 当有人已经为 map 获取了 Lock() 时会发生什么,其他 go-routine 是否仍然可以获取 RLock()
- 如果某人 X 已经获取了 Lock(),那么其他获取 RLock() 的 go-routine 将不得不等到 X 释放锁(Unlock())
3)假设我们这里处理的是Maps,有没有可能出现"concurrent read/write of Map"错误?
- 地图不是线程安全的。所以 "concurrent read/write of Map" 会导致错误。
有关更多说明,请参见以下示例:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
lock := sync.RWMutex{}
b := map[string]int{}
b["0"] = 0
go func(i int) {
lock.RLock()
fmt.Printf("RLock: from go routine %d: b = %d\n",i, b["0"])
time.Sleep(time.Second*3)
fmt.Printf("RLock: from go routine %d: lock released\n",i)
lock.RUnlock()
}(1)
go func(i int) {
lock.Lock()
b["2"] = i
fmt.Printf("Lock: from go routine %d: b = %d\n",i, b["2"])
time.Sleep(time.Second*3)
fmt.Printf("Lock: from go routine %d: lock released\n",i)
lock.Unlock()
}(2)
<-time.After(time.Second*8)
fmt.Println("*************************************8")
go func(i int) {
lock.Lock()
b["3"] = i
fmt.Printf("Lock: from go routine %d: b = %d\n",i, b["3"])
time.Sleep(time.Second*3)
fmt.Printf("Lock: from go routine %d: lock released\n",i)
lock.Unlock()
}(3)
go func(i int) {
lock.RLock()
fmt.Printf("RLock: from go routine %d: b = %d\n",i, b["3"])
time.Sleep(time.Second*3)
fmt.Printf("RLock: from go routine %d: lock released\n",i)
lock.RUnlock()
}(4)
<-time.After(time.Second*8)
}