【问题标题】:Race conditions in io.Pipe?io.Pipe 中的竞争条件?
【发布时间】:2016-03-07 21:46:32
【问题描述】:

我有一个函数,它返回 io.PipeReader 端并启动一个 go-routine,它将数据写入它的 Writer 端,然后关闭管道。

func GetPipeReader() io.ReadCloser {
    r, w := io.Pipe()
    go func() {
        _, err := io.CopyN(w, SomeReaderOfSize(N), N)
        w.CloseWithError(err)
    }()
    return r
}

func main() {
    var buf bytes.Buffer
    io.Copy(&buf, GetPipeReader())
    println("got", buf.Len(), "bytes")
}

https://play.golang.org/p/OAijIwmtRr

这似乎在我的测试中总是有效的,因为我得到了我写的所有数据。但是API docs 让我有点担心:

func Pipe() (*PipeReader, *PipeWriter)

Pipe 创建一个同步的内存管道。 [...] 一端的读数是 与另一方面的写入相匹配,[...] 没有内部 缓冲。

func (w *PipeWriter) CloseWithError(err error) 错误

CloseWithError 关闭写入器;读取一半的后续读取 的管道将不返回任何字节和错误 err,或者如果 err 是 EOF 无。

我想知道的是,这里可能的竞争条件是什么?我的 go-routine 会写入一堆数据,然后在我可以全部读取之前关闭管道,这是否合理?

我是否需要使用通道来发出一些关于何时关闭的信号?基本上会出什么问题。

【问题讨论】:

  • 文档提到“可以安全地同时调用 Read 和 Write 或关闭。一旦挂起的 I/O 完成,关闭将完成”,所以我看不出哪里可以一场比赛发生了。
  • 别担心,在比赛检测器下运行代码:-)。请注意,读取和写入是匹配的:您写入的数据在您写入的那一刻被读取。只是在关闭删除数据后读取。只需确保读取确实消耗了您想要写入的所有内容。
  • 种族检测器?!太棒了,我没有意识到there was such a thing。现在来看看。我稍后会玩它。

标签: go io race-condition


【解决方案1】:

不,没有竞争条件。正如文档所述,一端的读取与另一端的写入匹配。因此,当到达CloseWithError() 时,意味着每个Write 都已成功完成并与相应的Read 匹配 - 所以另一端一定已经阅读了所有要阅读的内容。

【讨论】:

    猜你喜欢
    • 2011-07-17
    • 2013-02-27
    • 2021-04-16
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 2018-10-08
    相关资源
    最近更新 更多