kotlinx.coroutines: Can't join a canceled task

Hi,

In the following code, I want to make sure my code blocks until the task is really finished:

        val job = async(CommonPool) {
            while (isActive);
            Thread.sleep(1000)
            System.out.println("end of async")
        }

        job.cancel()
        job.join()
        System.out.println("end of test")

The result is that I see “end of test” instantly, and “end of async” appears a second after, even though I asked to join() the task. Am I misusing the library or is this a bug?

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 2
  • Comments: 21 (15 by maintainers)

Most upvoted comments

I’ve pushed the corresponding changes to the develop branch. Now jobs (including Deferred) have an additional cancelling state. So, on invocation of cancel they go into cancelling state. isActive starts returning false, but isComplete is still false in this state. Both join and await wait for completion, that is they wait until the coroutine completes it execution.

It is important to note, that in current implementation a cancelled coroutine is doomed to complete exceptionally. Even if CancellationException is caught inside a coroutine and is replaced with any kind of result, it will still go into cancelled state on completion.

Note, that the naming of various states (see docs on Job and Deferred) are still under consideration and may change: https://github.com/Kotlin/kotlinx.coroutines/blob/develop/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Job.kt

The reason to change the implementation of join and await is two-fold. One is consistency with Thread.join as was mentioned above, but that would not be so compelling if not for the other. The other is to ensure that async(context) { doSomething() }.await() is really working just as run(context) { doSomething() } without any spurious concurrency on cancellation. This is what really bothers me in the current (version <= 0.16) implementation of join and await, it is that when I cancel the coroutine, then the other coroutine that was waiting for it is going to be executed concurrently with whatever code that was still running in the coroutine that was cancelled, but has not completed just yet. This concurrency would be so rare, that it would be a source of very hard-to-diagnose bugs.

Released in version 0.17

I plan to get it released soon (this or next week)