我当时在想Go中的mutex
会锁定数据,并且除非第一个goroutine
释放锁定,否则不允许其他任何goroutine
进行读取/写入。看来我的理解是错误的。阻止从其他goroutine
读取/写入的唯一方法是也调用其他lock
中的goroutines
。这样可以确保只有一个critical section
可以访问goroutine
。
因此,我希望this代码出现死锁:
package main
import(
"fmt"
"sync"
)
type myMap struct {
m map[string]string
mutex sync.Mutex
}
func main() {
done := make(chan bool)
ch := make(chan bool)
myM := &myMap{
m: make(map[string]string),
}
go func() {
myM.mutex.Lock()
myM.m["x"] = "i"
fmt.Println("Locked. Won't release the Lock")
ch <- true
}()
go func() {
<- ch
fmt.Println("Trying to write to the myMap")
myM.m["a"] = "b"
fmt.Println(myM)
done <- true
}()
<- done
}
由于第一个goroutine
锁定了该结构,因此我希望第二个goroutine
无法读取/写入该结构,但是这种情况不会在这里发生。如果我将
mux.Lock()
添加到第二个goroutine
中,那么将出现死锁。我发现
mutex
在Go中的工作方式有点怪异。如果我锁定了,那么Go不应允许任何其他goroutine
对其进行读写。有人可以向我解释Go中的互斥量概念吗?
最佳答案
互斥锁周围没有神奇的力场,可以保护它恰好嵌入其中的任何数据结构。如果锁定了互斥锁,它将阻止其他代码对其进行锁定直到被解锁。仅此而已。 It's well documented in the sync
package.
因此,在您的代码中,只有一个myM.mutex.Lock()
,其效果与没有互斥锁的效果相同。
正确使用保护数据的互斥锁涉及在更新或读取数据之前锁定互斥锁,然后再对其进行解锁。通常,此代码将包装在一个函数中,以便可以使用defer:
func doSomething(myM *myMap) {
myM.mutex.Lock()
defer myM.mutex.Unlock()
... read or update myM
}
关于multithreading - 了解互斥行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63434403/