假设我有很多 goroutine 在做这样的事情:
func (o *Obj) Reader() {
data := o.data;
for i, value := range data {
log.Printf("got data[%v] = %v", i, value)
}
}
Run Code Online (Sandbox Code Playgroud)
一个这样做:
func (o *Obj) Writer() {
o.data = append(o.data, 1234)
}
Run Code Online (Sandbox Code Playgroud)
如果data := o.data
意味着切片的内部结构被复制,这看起来可能是安全的,因为我从不修改副本的可访问范围内的任何内容。我要么在范围之外设置一个元素并增加长度,要么分配一个全新的指针,但读者将在原始指针上进行操作。
我的假设是否正确,这样做是否安全?
我知道切片通常并不意味着“线程安全”,问题更多地是关于slice1 := slice2
实际复制了多少。
问题中的代码是不安全的,因为它读取一个 goroutine 中的变量并在没有同步的情况下修改另一个 goroutine 中的变量。
这是使代码安全的一种方法:
type Obj struct {
mu sync.Mutex // add mutex
... // other fields as before
}
func (o *Obj) Reader() {
o.mu.Lock()
data := o.data
o.mu.Unlock()
for i, value := range data {
log.Printf("got data[%v] = %v", i, value)
}
}
func (o *Obj) Writer() {
o.mu.Lock()
o.data = append(o.data, 1234)
o.mu.Unlock()
}
Run Code Online (Sandbox Code Playgroud)
Reader
对局部切片变量进行范围是安全的,data
因为Writer
它不会修改局部变量data
或通过局部变量可见的后备数组data
。