marc wellman
marc wellman

Reputation: 5886

How to check whether a go channel is actually waiting for data?

I want to only proceed with my execution when a certain channel blocks waiting for data to come (the blocking channel is part of a working go routine, supposed to run in parallel).

Like:

func foo(c chan bool) {

    go start_blocking(c)
    
    // only come here, when channel c actually blocks!
}

func start_blocking(c chan bool) {

    <-c
}

How to achieve this?

Purpose:

The channel is waiting for data to come at some time later and it should be ready in the background, before the main execution continues.

Upvotes: 2

Views: 5381

Answers (2)

jub0bs
jub0bs

Reputation: 66354

Channels don't block; it's communications (send or receive) on them that may block.

Checking whether a channel communication would block without actually attempting the communication in question is not very idiomatic in Go, for reasons discussed below. However, if that's really what you want, you could do the following. For a given (buffered!) channel ch, you could

  • check len(ch) == cap(ch) to determine whether a send would block;
  • check len(ch) == 0 to determine whether a receive would block.

However, both checks are likely to become stale very quickly, because another goroutine may have sent to or received from the channel shortly after your check; a classic instance of time-of-check to time-of-use (TOCTOU).

And as pointed out in the comments, one caveat of this approach is that it doesn't work for unbuffered channels, for which the two conditions invariably evaluate to true.

Upvotes: 4

icza
icza

Reputation: 418337

You can't "peek" a channel without actually receiving from it. So channels are not a good tool if you really need this functionality. If you have a buffered channel, you can of course check if there's a value in its buffer by checking its length (len(ch)), but there's no guarantee the value can still be received if you attempt to do it afterwards.

If you do need this functionality, use a counter instead with atomic reads and writes. It is possible to read a counter's value without decrementing it.

And if you do need a channel, using a select with default case should suffice: you may do non-blocking send and receive, and if a send or receive would block, the default case will be executed without blocking.

Upvotes: 5

Related Questions