首頁 > 後端開發 > Golang > 嘗試寫入/讀取時 io.Pipe 和死鎖

嘗試寫入/讀取時 io.Pipe 和死鎖

王林
發布: 2024-02-06 09:40:03
轉載
1180 人瀏覽過

尝试写入/读取时 io.Pipe 和死锁

問題內容

我花了幾個小時嘗試理解底層邏輯,但沒有任何進展。下面的程式碼在第一次迭代後返回死鎖。如果我在 io.copy 之前關閉 writer,死鎖就會消失,但不會列印任何內容(因為管道寫入端在讀取之前已關閉)

func main() {
    reader, writer := io.pipe()
    c := make(chan string)

    go func() {
        for i := 0; i < 5; i++ {
            text := fmt.sprintf("hello %vth time", i+1)
            c <- text
        }

        close(c)
    }()

    for msg := range c {
        msg = fmt.sprintf("\nreceived from channel -> %v\n", msg)

        go fmt.fprint(writer, msg)
        io.copy(os.stdout, reader)
        writer.close()
    }

}
登入後複製

這是運行程式碼後的錯誤

received from channel -> hello 1th time fatal error: all goroutines
are asleep - deadlock!
goroutine 1 [select]: io.(*pipe).read(0xc000130120, {0xc00013e000,
0x8000, 0xc00011e001?})
/usr/lib/go/src/io/pipe.go:57 +0xb1 io.(*PipeReader).Read(0x0?, {0xc00013e000?, 0xc00011e050?, 0x10?})
/usr/lib/go/src/io/pipe.go:136 +0x25 io.copyBuffer({0x4bde98, 0xc00011e050}, {0x4bddb8, 0xc00012e018}, {0x0, 0x0, 0x0})
/usr/lib/go/src/io/io.go:427 +0x1b2 io.Copy(...)
/usr/lib/go/src/io/io.go:386 os.genericReadFrom(0x101c00002c500?, {0x4bddb8, 0xc00012e018})
/usr/lib/go/src/os/file.go:161 +0x67 os.(*File).ReadFrom(0xc00012e008, {0x4bddb8, 0xc00012e018})
/usr/lib/go/src/os/file.go:155 +0x1b0 io.copyBuffer({0x4bde38, 0xc00012e008}, {0x4bddb8, 0xc00012e018}, {0x0, 0x0, 0x0})
/usr/lib/go/src/io/io.go:413 +0x14b io.Copy(...)
/usr/lib/go/src/io/io.go:386 main.pipetest()
/home/stranger/source-code/golang/ipctest/pipes/main.go:39 +0x1ae main.main()
/home/stranger/source-code/golang/ipctest/pipes/main.go:10 +0x17
goroutine 18 [chan send]: main.pipetest.func1()
/home/stranger/source-code/golang/ipctest/pipes/main.go:29 +0x85 created by main.pipetest
/home/stranger/source-code/golang/ipctest/pipes/main.go:26 +0x17a exit status 2
登入後複製


正確答案


io.copy 不斷嘗試複製,直到讀取器到達eof(在本例中,當管道關閉時)。由於您在io.copy 結束後呼叫writer.close() after ,因此io.copy 將永遠不會看到eof,並永遠掛起。

程式碼的另一個問題是您嘗試多次關閉管道(每次循環程式碼重複時)。一般情況下,closeable 物件只應關閉一次,並且在 closed 後被假定為不可用。如果您需要重新使用它們,您應該建立一個新實例。

這是程式碼的工作修訂版:

func main() {
    c := make(chan string)

    go func() {
        for i := 0; i < 5; i++ {
            text := fmt.Sprintf("hello %vth time", i+1)
            c <- text
        }

        close(c)
    }()

    for msg := range c {
        msg = fmt.Sprintf("\nreceived from channel -> %v\n", msg)

        // Create a new pipe for this message.
        reader, writer := io.Pipe()
        go func() {
            fmt.Fprint(writer, msg)
            // Close the pipe after writing the message.
            writer.Close()
        }()

        io.Copy(os.Stdout, reader)
    }
}
登入後複製

以上是嘗試寫入/讀取時 io.Pipe 和死鎖的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:stackoverflow.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板