Heim  >  Artikel  >  Backend-Entwicklung  >  Deadlock beim Warten auf Pipe io.Copy in Goroutine

Deadlock beim Warten auf Pipe io.Copy in Goroutine

PHPz
PHPznach vorne
2024-02-15 15:10:08550Durchsuche

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

Deadlock beim Warten auf Pipeline io.Copy in Goroutine ist ein häufiges Problem. Wenn wir auf den Abschluss von io.Copy in einer Goroutine warten und die Pipe nicht ordnungsgemäß geschlossen wird, führt dies zu einem Deadlock. In diesem Fall wartet Goroutine weiterhin auf Daten und kann die Ausführung nicht fortsetzen. Die Lösung für dieses Problem besteht darin, die Pipe nach Abschluss von io.Copy manuell zu schließen, um sicherzustellen, dass die Goroutine ordnungsgemäß beendet werden kann. Der PHP-Editor Apple hat die Ursachen und Lösungen für dieses Problem ausführlich vorgestellt und hofft, Ihnen dabei zu helfen, besser mit dieser Art von Deadlock-Situation umzugehen.

Frageninhalt

Im folgenden Code ist die Funktion für 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()
}

Ausgabe:

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

Hier ist der Playground-Link zum Code: https://goplay.tools/snippet/70ubgiz8ftv

Gibt es eine Möglichkeit, Deadlocks zu vermeiden und gleichzeitig io.pipe beizubehalten?

Workaround

Schließen Sie das schreibende Ende der Pfeife, wenn Sie fertig sind:

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

Sonst wartet der Leser ewig.

Das obige ist der detaillierte Inhalt vonDeadlock beim Warten auf Pipe io.Copy in Goroutine. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen