Locks
sync包实现两种锁数据类型,sync.Mutex和sync.RWMutex.
var l sync.Mutex
var a string
func f() {
a = "hello, world"
l.Unlock()
}
func main() {
l.Lock()
go f()
l.Lock()
print(a)
}
l.Lock()第一次加锁,然后执行执行函数,等变量a赋值完成后将全局锁释放。l.Lock()能够加到锁的时候,表示f函数已经执行完成。那问题来了,打印完a.Lock,程序运行结束,锁释放需要手动吗?自动释放比手动释放更合理吗?其实本质是一样的,只是手动会多执行一次。
Once
当使用Once.Do(f)时,只有一个线程可以执行这个f函数,只有当f函数执行完成,其他线程才有机会执行f函数。代码示例如下:
var a string
var once sync.Once
func setup() {
a = "hello, world"
}
func doprint() {
once.Do(setup)
print(a)
}
func twoprint() {
go doprint()
go doprint()
}
错误示例
var a, b int
func f() {
a = 1
b = 2
}
func g() {
print(b)
print(a)
}
func main() {
go f()
g()
}
f函数和g函数同时执行,所以输出结果不确定,不能达到预期。结果可能是0,1。
var a string
var done bool
func setup() {
a = "hello, world"
done = true
}
func doprint() {
if !done {
once.Do(setup)
}
print(a)
}
func twoprint() {
go doprint()
go doprint()
}
双重锁校验,但是不能保证输出的结果为hello,world,有可能输出为空。
var a string
var done bool
func setup() {
a = "hello, world"
done = true
}
func main() {
go setup()
for !done {
}
print(a)
}
当主函数执行到for !done时,done可能不为true,所以主函数一直阻塞在这个循环体。
type T struct {
msg string
}
var g *T
func setup() {
t := new(T)
t.msg = "hello, world"
g = t
}
func main() {
go setup()
for g == nil {
}
print(g.msg)
}
即使g可能不为nil,但是g.msg可能为空。