Stopping goroutines blocked on reading

1,593 views
Skip to first unread message

Evan Shaw

unread,
Oct 27, 2014, 4:20:13 PM10/27/14
to golang-nuts
Say I have a function something like this: http://play.golang.org/p/Ry0S399DkP

It reads from an io.Reader and sends the bytes it reads on a channel until it can receive from the done channel.

The problem is, once a value's ready on the done channel, the goroutine still has to wait for Read before it can receive. This can take an arbitrarily long amount of time depending on the Reader.

I can close the Reader from another goroutine, but then I end up logging the error from Read, and there's no good way to filter out the expected "this Reader is closed" error. If it happens often, logs are full of clutter.

Is there a solution, aside from writing fragile code to detect the "this Reader is closed" error for every type of Reader imaginable?

- Evan

Dave Cheney

unread,
Oct 27, 2014, 4:33:38 PM10/27/14
to golan...@googlegroups.com
When the reader is closed you get io.EOF. Also remember that a reader can return some bytes (that is n > 0), and an error at the same time, so you also need to handle that condition.

Evan Shaw

unread,
Oct 27, 2014, 5:56:49 PM10/27/14
to Dave Cheney, golang-nuts
Some Readers may return io.EOF when they're closed, but I haven't seen any that do. Here's an example (run locally because the playground has no stdin): http://play.golang.org/p/qcGe987Mip

When I run this example, I get:

error reading: read /dev/stdin: bad file descriptor

The behavior is the same when the Reader gets closed while a Read is happening concurrently. And if I do the same thing with a TCP connection, I get a different error that requires different logic to catch.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Dave Cheney

unread,
Oct 27, 2014, 6:06:26 PM10/27/14
to Evan Shaw, golang-nuts
Yes, sadly posix doesn't specify what happens if you close an fd that
has a concurrent read waiting on it. We work around this for network
sockets, but the remaining blocking reads are still a problem.

https://code.google.com/p/go/issues/detail?id=6817 and friends.

Evan Shaw

unread,
Oct 27, 2014, 6:17:28 PM10/27/14
to Dave Cheney, golang-nuts
Thanks, I didn't find that issue in my searches.

It appears I was a little turned around on my code sample and that a TCP connection does return EOF. It's *writing* to a closed TCP connection that returns a difficult-to-catch error.

James Bardin

unread,
Oct 27, 2014, 6:17:48 PM10/27/14
to golan...@googlegroups.com, eds...@gmail.com
I wonder if there is any way to currently do this reliably, even disregarding errors. Trying to break a read on a FIFO hangs:

Dave Cheney

unread,
Oct 27, 2014, 6:21:20 PM10/27/14
to James Bardin, golang-nuts, Evan Shaw
Not really, the fix is to make all fd io go through a poller, not just
socket io.
> You received this message because you are subscribed to a topic in the
> Google Groups "golang-nuts" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/golang-nuts/byfD0YtIl0I/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to

James Bardin

unread,
Oct 27, 2014, 6:26:21 PM10/27/14
to golan...@googlegroups.com, da...@cheney.net


On Monday, October 27, 2014 6:17:28 PM UTC-4, Evan Shaw wrote:
Thanks, I didn't find that issue in my searches.

It appears I was a little turned around on my code sample and that a TCP connection does return EOF. It's *writing* to a closed TCP connection that returns a difficult-to-catch error.


A Read from a TCP can still return a somewhat generic "use of closed network connection" (with no useful type, so you would end up string-matching for this). The nice way to break a Read in this case at least, is first call conn.CloseRead() which will return EOF, then you can fully close the connection. 

Nick Patavalis

unread,
Oct 28, 2014, 10:33:11 AM10/28/14
to golan...@googlegroups.com, eds...@gmail.com
I believe this does what you want. Use fd's from mutiple goroutines reliably, and stop blocked calls safely:


/npat
Reply all
Reply to author
Forward
0 new messages