将 append() 附加到另一个线程正在读取的切片是否安全?

Luk*_*ský 5 go

假设我有很多 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实际复制了多少。

Cer*_*món 6

问题中的代码是不安全的,因为它读取一个 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

  • 很酷,所以这意味着切片的“浅拷贝”对于其他 Goroutine 中的 `append()` 所做的任何事情都是安全的?在实践中,我会在那里使用“RWLock”,但如果能保证它能工作那就太好了。 (2认同)