Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Deadlock while waiting for piped io.Copy in Goroutine

In the code below, the call to io.Copy never returns; it just blocks indefinitely, causing a deadlock. This behaviour only occurs when the io.Pipe is used to connect the read io.Reader to the os.Stdout io.Writer. However, I need to use the pipe since, in my full code, I am using io.MultiWriter with io.Pipes to connect one io.Reader to many functions expecting an 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()
}

Output:

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

Here is a playground link to the code: https://goplay.tools/snippet/70UbGIz8fTV

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Is there any way to avoid the deadlock while keeping the io.Pipe?

>Solution :

Close the writing end of the pipe when done:

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

Without that, the reader end will wait indefinitely.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading