【发布时间】:2017-02-24 17:57:42
【问题描述】:
我知道 golang 的 bytes.Buffer 不是线程安全的,但如果我有一个编写器(在一个 goroutine 中)和一个阅读器(在另一个 goroutine 中)。安全吗?
如果不是,那为什么不是呢?写入追加到缓冲区,而读取从头开始读取,所以我看不到他们将访问相同内存位置的情况。
【问题讨论】:
我知道 golang 的 bytes.Buffer 不是线程安全的,但如果我有一个编写器(在一个 goroutine 中)和一个阅读器(在另一个 goroutine 中)。安全吗?
如果不是,那为什么不是呢?写入追加到缓冲区,而读取从头开始读取,所以我看不到他们将访问相同内存位置的情况。
【问题讨论】:
不,这不安全。
bytes.Buffer 是一个结构,Buffer.Read() 和Buffer.Write() 方法都读取/修改相同结构值的相同字段(它们具有指针接收器)。仅此一项就足以使并发使用不安全。更多详情请见Is it safe to read a function pointer concurrently without a lock?
还可以考虑bytes.Buffer 将字节存储在字节片中,这是结构体的一个字段。写入时,有时可能需要分配更大的缓冲区(如果切片容量不够),因此必须更改切片头(切片结构字段)(在Write() 中)。如果没有同步,就不能保证并发的Read() 会看到这个。
而且...即使不需要重新分配(因为底层字节切片有足够的容量来容纳传递给Write()的数据),将数据存储在字节切片中也需要对其进行重新切片,因此切片头会发生变化即使不需要重新分配(切片的长度也是切片头的一部分)。要查看切片标头中的内容,请查看 reflect.SliceHeader 类型。
【讨论】: