首頁  >  文章  >  後端開發  >  在 Goroutine 中等待管道 io.Copy 時發生死鎖

在 Goroutine 中等待管道 io.Copy 時發生死鎖

PHPz
PHPz轉載
2024-02-15 15:10:08553瀏覽

在 Goroutine 中等待管道 io.Copy 时发生死锁

在 Goroutine 中等待管道 io.Copy 時發生死鎖是一個常見的問題。當我們在一個 Goroutine 中等待 io.Copy 的完成時,如果管道沒有被正確地關閉,就會導致死鎖。在這種情況下,Goroutine 會一直在等待數據,而無法繼續執行。解決這個問題的方法是,在 io.Copy 完成後,手動關閉管道,以確保 Goroutine 可以正確結束。 php小編蘋果為你詳細介紹了這個問題的原因和解決方法,希望能幫助你更好地處理這類死鎖狀況。

問題內容

在下面的程式碼中,對 io.copy 的呼叫永遠不會回傳;它只是無限期地阻塞,導致死鎖。只有當使用 io.pipeio.reader 連接到 os.stdout io.writer 時,才會發生此行為。但是,我需要使用管道,因為在我的完整程式碼中,我使用io.multiwriterio.pipes 將一個io.reader 連接到許多需要io.reader 的函數。

func main() {
    read := strings.newreader("abcdefghij")
    pipereader, pipewriter := io.pipe()

    var wg sync.waitgroup
    wg.add(1)
    go func() {
        println("start copy")
        _, err := io.copy(os.stdout, pipereader)
        if err != nil {
            println(err.error())
        }
        println("end copy")
        wg.done()
    }()

    _, err := io.copy(pipewriter, read)
    if err != nil {
        println(err.error())
    }

    wg.wait()
}

輸出:

Start copy
abcdefghij
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc0000b0018?)
    /usr/local/go-faketime/src/runtime/sema.go:62 +0x25
sync.(*WaitGroup).Wait(0x4969c8?)
    /usr/local/go-faketime/src/sync/waitgroup.go:139 +0x52
main.main()
    /tmp/sandbox4108076976/prog.go:31 +0x23c

goroutine 18 [select]:
io.(*pipe).read(0xc0000a6120, {0xc0000b6000, 0x8000, 0xc00009e101?})
    /usr/local/go-faketime/src/io/pipe.go:57 +0xb1
io.(*PipeReader).Read(0x10?, {0xc0000b6000?, 0xc00009e1e0?, 0x4f75a0?})
    /usr/local/go-faketime/src/io/pipe.go:136 +0x25
io.copyBuffer({0x496aa8, 0xc00009e1e0}, {0x4969a8, 0xc0000a4018}, {0x0, 0x0, 0x0})
    /usr/local/go-faketime/src/io/io.go:427 +0x1b2
io.Copy(...)
    /usr/local/go-faketime/src/io/io.go:386
os.genericReadFrom(0xb000000006018ab?, {0x4969a8, 0xc0000a4018})
    /usr/local/go-faketime/src/os/file.go:162 +0x67
os.(*File).ReadFrom(0xc0000a4008, {0x4969a8, 0xc0000a4018})
    /usr/local/go-faketime/src/os/file.go:156 +0x1b0
io.copyBuffer({0x496a28, 0xc0000a4008}, {0x4969a8, 0xc0000a4018}, {0x0, 0x0, 0x0})
    /usr/local/go-faketime/src/io/io.go:413 +0x14b
io.Copy(...)
    /usr/local/go-faketime/src/io/io.go:386
main.main.func1()
    /tmp/sandbox4108076976/prog.go:18 +0x71
created by main.main
    /tmp/sandbox4108076976/prog.go:16 +0x1d3

這裡是程式碼的遊樂場連結:https://goplay.tools/snippet/70ubgiz8ftv

有沒有辦法在保留 io.pipe 的同時避免死鎖?

解決方法

完成後關閉管道的寫入端:

_, err := io.Copy(pipeWriter, read)
pipeWriter.Close()
if err != nil {
    println(err.Error())
}

否則,讀者端將無限期地等待。

以上是在 Goroutine 中等待管道 io.Copy 時發生死鎖的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除