Skip to content

Commit 2f4490e

Browse files
committed
Extend the documentation for ProducerScope.awaitClose
Filed Kotlin#4149
1 parent 1b70f42 commit 2f4490e

File tree

1 file changed

+19
-8
lines changed
  • kotlinx-coroutines-core/common/src/channels

1 file changed

+19
-8
lines changed

kotlinx-coroutines-core/common/src/channels/Produce.kt

+19-8
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,36 @@ public interface ProducerScope<in E> : CoroutineScope, SendChannel<E> {
1919
}
2020

2121
/**
22-
* Suspends the current coroutine until the channel is either [closed][SendChannel.close] or [cancelled][ReceiveChannel.cancel]
23-
* and invokes the given [block] before resuming the coroutine.
22+
* Suspends the current coroutine until the channel is either
23+
* [closed][SendChannel.close] or [cancelled][ReceiveChannel.cancel].
2424
*
25-
* This suspending function is cancellable: if the [Job] of the current coroutine is cancelled while this
26-
* suspending function is waiting, this function immediately resumes with [CancellationException].
25+
* The given [block] will be executed unconditionally before this function returns.
26+
* `awaitClose { cleanup() }` is a convenient shorthand for the often useful form
27+
* `try { awaitClose() } finally { cleanup() }`.
28+
*
29+
* This function can only be invoked directly inside the same coroutine that is its receiver.
30+
* Specifying the receiver of [awaitClose] explicitly is most probably a mistake.
31+
*
32+
* This suspending function is cancellable: if the [Job] of the current coroutine is [cancelled][CoroutineScope.cancel]
33+
* while this suspending function is waiting, this function immediately resumes with [CancellationException].
2734
* There is a **prompt cancellation guarantee**: even if this function is ready to return, but was cancelled
2835
* while suspended, [CancellationException] will be thrown. See [suspendCancellableCoroutine] for low-level details.
2936
*
30-
* Note that when the producer channel is cancelled, this function resumes with a cancellation exception.
31-
* Therefore, in case of cancellation, no code after the call to this function will be executed.
32-
* That's why this function takes a lambda parameter.
33-
*
3437
* Example of usage:
3538
* ```
3639
* val callbackEventsStream = produce {
3740
* val disposable = registerChannelInCallback(channel)
3841
* awaitClose { disposable.dispose() }
3942
* }
4043
* ```
44+
*
45+
* **Pitfall**: when used in [produce], if the channel is [cancelled][ReceiveChannel.cancel], [awaitClose] can either
46+
* return normally or throw a [CancellationException] due to a race condition.
47+
* The reason is that, for [produce], cancelling the channel and cancelling the coroutine of the [ProducerScope] is
48+
* done simultaneously.
49+
*
50+
* @throws IllegalStateException if invoked from outside the [ProducerScope] (by leaking `this` outside the producer
51+
* coroutine).
4152
*/
4253
public suspend fun ProducerScope<*>.awaitClose(block: () -> Unit = {}) {
4354
check(kotlin.coroutines.coroutineContext[Job] === this) { "awaitClose() can only be invoked from the producer context" }

0 commit comments

Comments
 (0)