我可以使用锁来确保指令顺序吗?
Can I use lock to ensure instruction order?
如本 link https://golang.org/ref/mem 所述,以下代码使用了不正确的同步:
var a, b int
func f() {
a = 1
b = 2
}
func g() {
print(b)
print(a)
}
func main() {
go f()
g()
}
因为它可能会打印 a = 0 和 b = 2。
但是,我想知道在下面的代码中是否可能出现这种结果,其中 a 和 b 受 Lock 保护:
var a, b int
var mu sync.Mutex
func f() {
mu.Lock()
a = 1
b = 2
mu.Unlock()
}
func g() {
mu.Lock()
print(b)
print(a)
mu.Unlock()
}
func main() {
go f()
g()
}
因为 link 说:
For any sync.Mutex or sync.RWMutex variable l and n < m, call n of l.Unlock() happens before call m of l.Lock() returns.
但是不清楚a和b的赋值是否保证在Unlock
语句
之前执行
保证一旦f
执行mu.Unlock()
,所有读取a
和b
的goroutines都会看到a
和[=的更新值13=] 如果这些 goroutines 也使用相同的锁访问 a
和 b
。如果有 goroutines 在没有锁定的情况下读取 a
和 b
那么就会有一场比赛。
代码是安全的,因为它没有数据竞争。
虽然没有定义行为。关于goroutine调度没有同步,所以可能是g()
先锁住mutex,一旦释放,main()
结束,你的app可能会随之结束,而f()
可能不会完成(甚至可能不会开始)。该应用程序可能不打印任何内容,可能会打印 2
,或者可能会打印 21
.
也可能是f()
先加锁,进行赋值,然后g()
in main()
打印赋值的新值:21
.
如果要f()
先赋值,可以使用sync.WaitGroup
,例如:
var a, b int
var wg sync.WaitGroup
func f() {
defer wg.Done()
a = 1
b = 2
}
func g() {
print(b)
print(a)
}
func main() {
wg.Add(1)
go f()
wg.Wait()
g()
}
这将始终打印 21
,请在 Go Playground 上尝试。
还有一个复杂的例子来证明它也可以用 sync.Mutex
来解决。这不是它的设计用途,但这也有效:
在 main()
中锁定 mu
,然后再启动 goroutine。有 g()
也加锁,一开始显然会阻塞。 f()
可以在它的工作完成后解锁它,将 "green light" 给 g()
:
var a, b int
var mu sync.Mutex
func f() {
a = 1
b = 2
mu.Unlock()
}
func g() {
mu.Lock()
print(b)
print(a)
mu.Unlock()
}
func main() {
mu.Lock()
go f()
g()
}
在 Go Playground 上试试这个。
如本 link https://golang.org/ref/mem 所述,以下代码使用了不正确的同步:
var a, b int
func f() {
a = 1
b = 2
}
func g() {
print(b)
print(a)
}
func main() {
go f()
g()
}
因为它可能会打印 a = 0 和 b = 2。
但是,我想知道在下面的代码中是否可能出现这种结果,其中 a 和 b 受 Lock 保护:
var a, b int
var mu sync.Mutex
func f() {
mu.Lock()
a = 1
b = 2
mu.Unlock()
}
func g() {
mu.Lock()
print(b)
print(a)
mu.Unlock()
}
func main() {
go f()
g()
}
因为 link 说:
For any sync.Mutex or sync.RWMutex variable l and n < m, call n of l.Unlock() happens before call m of l.Lock() returns.
但是不清楚a和b的赋值是否保证在Unlock
语句
保证一旦f
执行mu.Unlock()
,所有读取a
和b
的goroutines都会看到a
和[=的更新值13=] 如果这些 goroutines 也使用相同的锁访问 a
和 b
。如果有 goroutines 在没有锁定的情况下读取 a
和 b
那么就会有一场比赛。
代码是安全的,因为它没有数据竞争。
虽然没有定义行为。关于goroutine调度没有同步,所以可能是g()
先锁住mutex,一旦释放,main()
结束,你的app可能会随之结束,而f()
可能不会完成(甚至可能不会开始)。该应用程序可能不打印任何内容,可能会打印 2
,或者可能会打印 21
.
也可能是f()
先加锁,进行赋值,然后g()
in main()
打印赋值的新值:21
.
如果要f()
先赋值,可以使用sync.WaitGroup
,例如:
var a, b int
var wg sync.WaitGroup
func f() {
defer wg.Done()
a = 1
b = 2
}
func g() {
print(b)
print(a)
}
func main() {
wg.Add(1)
go f()
wg.Wait()
g()
}
这将始终打印 21
,请在 Go Playground 上尝试。
还有一个复杂的例子来证明它也可以用 sync.Mutex
来解决。这不是它的设计用途,但这也有效:
在 main()
中锁定 mu
,然后再启动 goroutine。有 g()
也加锁,一开始显然会阻塞。 f()
可以在它的工作完成后解锁它,将 "green light" 给 g()
:
var a, b int
var mu sync.Mutex
func f() {
a = 1
b = 2
mu.Unlock()
}
func g() {
mu.Lock()
print(b)
print(a)
mu.Unlock()
}
func main() {
mu.Lock()
go f()
g()
}
在 Go Playground 上试试这个。