File tree Expand file tree Collapse file tree 2 files changed +36
-1
lines changed
kotlinx-coroutines-core/src
main/kotlin/kotlinx/coroutines/experimental/channels
test/kotlin/kotlinx/coroutines/experimental/channels Expand file tree Collapse file tree 2 files changed +36
-1
lines changed Original file line number Diff line number Diff line change @@ -47,6 +47,11 @@ public interface SendChannel<in E> {
47
47
* or throws [ClosedSendChannelException] if the channel [isClosedForSend] _normally_.
48
48
* It throws the original [close] cause exception if the channel has _failed_.
49
49
*
50
+ * Note, that closing a channel _after_ this function had suspended does not cause this suspended send invocation
51
+ * to abort, because closing a channel is conceptually like sending a special "close token" over this channel.
52
+ * All elements that are sent over the channel are delivered in first-in first-out order. The element that
53
+ * is being sent will get delivered to receivers before a close token.
54
+ *
50
55
* This suspending function is cancellable. If the [Job] of the current coroutine is completed while this
51
56
* function is suspended, this function immediately resumes with [CancellationException].
52
57
* Cancellation of suspended send is *atomic* -- when this function
@@ -77,7 +82,7 @@ public interface SendChannel<in E> {
77
82
/* *
78
83
* Closes this channel with an optional exceptional [cause].
79
84
* This is an idempotent operation -- repeated invocations of this function have no effect and return `false`.
80
- * Conceptually, its sends a special close token of this channel. Immediately after invocation of this function
85
+ * Conceptually, its sends a special " close token" over this channel. Immediately after invocation of this function
81
86
* [isClosedForSend] starts returning `true`. However, [isClosedForReceive][ReceiveChannel.isClosedForReceive]
82
87
* on the side of [ReceiveChannel] starts returning `true` only after all previously sent elements
83
88
* are received.
Original file line number Diff line number Diff line change @@ -20,6 +20,8 @@ import kotlinx.coroutines.experimental.TestBase
20
20
import kotlinx.coroutines.experimental.launch
21
21
import kotlinx.coroutines.experimental.runBlocking
22
22
import kotlinx.coroutines.experimental.yield
23
+ import org.hamcrest.core.IsEqual
24
+ import org.hamcrest.core.IsNull
23
25
import org.junit.Assert.*
24
26
import org.junit.Test
25
27
@@ -247,6 +249,34 @@ class RendezvousChannelTest : TestBase() {
247
249
finish(10 )
248
250
}
249
251
252
+ @Test
253
+ fun testSuspendSendOnClosedChannel () = runBlocking<Unit > {
254
+ val q = RendezvousChannel <Int >()
255
+ expect(1 )
256
+ launch(context) {
257
+ expect(4 )
258
+ q.send(42 ) // suspend
259
+ expect(11 )
260
+ }
261
+ expect(2 )
262
+ launch(context) {
263
+ expect(5 )
264
+ q.close()
265
+ expect(6 )
266
+ }
267
+ expect(3 )
268
+ yield () // to sender
269
+ expect(7 )
270
+ yield () // try to resume sender (it will not resume despite the close!)
271
+ expect(8 )
272
+ assertThat(q.receiveOrNull(), IsEqual (42 ))
273
+ expect(9 )
274
+ assertThat(q.receiveOrNull(), IsNull ())
275
+ expect(10 )
276
+ yield () // to sender, it was resumed!
277
+ finish(12 )
278
+ }
279
+
250
280
class BadClass {
251
281
override fun equals (other : Any? ): Boolean = error(" equals" )
252
282
override fun hashCode (): Int = error(" hashCode" )
You can’t perform that action at this time.
0 commit comments