func main() { b := sync.Mutex{} b.Lock() fmt.Println("b已上锁") a := b a.Lock() fmt.Println("a已上锁") }
如以上代码显示,当a复制b的时候,b已经上锁了,所以a复制的是上锁状态下的b,所以这时a也是上锁状态,不能重复上锁,程序会报错,报错信息是死锁。
但是上面的问题我们能够一眼就看出,这时很明显的错误,但是有时候我们是不能一眼看出的,比如在结构体中有个锁,当我们复制结构体的时候就不一定能够一眼看出结构体的锁是上锁状态还是未上锁状态,甚至不知道结构体中是不是有锁,如:
type Person struct { mu sync.Mutex salary int lever int } func (p Person) do() { p.mu.Lock() p.salary = p.salary + 1000 p.lever = p.lever + 1 p.mu.Unlock() } func main() { b := Person{salary: 10000, lever: 1} go b.do() a := b go a.do() }
这时我们可以在命令行中用go vet 指令发现是否有锁拷贝的情况,如图:
再者,就还有数据竞争的问题,看以下代码
type Person struct { mu sync.Mutex salary int lever int } func (p *Person) do() { p.salary = p.salary + 1000 p.lever = p.lever + 1 } func main() { b := &Person{salary: 10000, lever: 1} for i := 0; i < 20000; i++ { go b.do() } time.Sleep(time.Second * 10) fmt.Println(b) } 运行后输出结果为
这个答案明显跟我们所想要的不一样,这涉及到了数据竞争的问题,就是太多协程同时在改同一个数据,会导致出错,这是我们要用race指令就可以查出错误了。如图
如图运行可执行文件后,它会报错
这个指令可以发现数据竞争的问题,这可能是加锁的建议,也有可能是bug的提醒