How do you tell when a channel is closed _while sending_?

88 Views Asked by At

The following hangs forever. I would like the suspend function to just return somehow if the send cannot complete.

suspend fun main() = coroutineScope {
    val channel = Channel<Int>()
    
    //channel.close()
    
    launch {
        println("closing")
        channel.close()
    }
    
    channel.send(0) // hangs forever!!
    println("end")
}

So basically what I need is a version of SendChannel.send that just throws or returns when the channel is closed while it's suspended.

1

There are 1 best solutions below

3
On BEST ANSWER

You said that you would like the send function to throw or return if the send cannot complete.

You have a rendezvous channel with no buffer, so send will always suspend until the channel's receive function is called. But that doesn't mean that your send call can't complete.

Even though the channel is closed, receive can still be called to successfully deliver a value that is already "in flight". In that case, the suspended send call will return normally.

The channel's order of operations is the same as the order that you called its functions in. A consumer reading from the channel will first see the value 0, and then will reach the end of the channel, because send was called before close.

This is mentioned explicitly in the documentation for the send function of a channel.

Closing a channel after this function has suspended does not cause this suspended send invocation to abort, because closing a channel is conceptually like sending a special "close token" over this channel. All elements sent over the channel are delivered in first-in first-out order. The sent element will be delivered to receivers before the close token.

The close function is part of the SendChannel interface and is intended for the sender to indicate that it isn't going to send any more values. It doesn't drop values that have already been sent, or are already in the process of being sent.

A channel also has a cancel function, which is part of the ReceiveChannel interface. The cancel function is intended for the receiver to indicate that it doesn't want to receive any more values. This will drop all the values that have already been sent, and will cause any ongoing send attempts to fail with an exception.

In your example code, if you replace channel.close() with channel.cancel(), the in-flight call to send will fail with an exception.