Courutines cancellation exceptions

Hey

For Kotlin Multiplatform projects: Is it possible to implement coroutines or threads for Kotlin/Native or Kotlin Coroutines that throw a cancellation exception?

Quote from this blog post where the problem of “Shrödinger’s Coroutines” is defined:

Cancellation exceptions shouldn’t be ignored or suppressed, because that could cause a cancelled coroutine to enter a zombie state where it can’t terminate and can’t do any work. But re-throwing every cancellation exception is flawed advice too, and could cause important coroutines to vanish silently instead of properly handling errors.

The problem is that there’s more than one possible source of cancellation exceptions, and handling them safely requires being able to tell them apart. The double-checked cancellation pattern uses ensureActive after catching an exception, allowing you to handle rogue cancellations as errors while letting real cancellation exceptions propagate correctly.

Maybe one could implement threading in the iosMain module?

Thanks.

ChatGPT says:

Yes, it is possible to implement coroutines or threads for Kotlin/Native in Kotlin Multiplatform projects. However, as you noted, handling cancellation exceptions properly is important to avoid issues like “Shrödinger’s Coroutines”.One way to handle cancellation exceptions is to use the double-checked cancellation pattern, which involves catching the exception and then using the ensureActive function to check if the coroutine is still active. If it is, the exception can be rethrown, but if not, it can be handled as an error.In terms of implementing threading in the iosMain module, it is definitely possible. Kotlin/Native provides support for POSIX threads, and there are several libraries available for managing threads and concurrency in Kotlin Multiplatform projects, such as kotlinx.coroutines and AtomicFusion.It’s important to note that while threads can be useful for managing concurrency in multiplatform projects, they can also introduce additional complexities and potential issues, such as race conditions and deadlocks. It’s important to use threading judiciously and carefully test your code to ensure that it works as intended.

Using the ensureActive function seems like a non-trivial workaround.

1 Like

I didn’t read the whole article carefully, but to be honest, I don’t get what’s the problem. The whole article is based on the case that if we throw CancellationException manually, that will kill the coroutine silently. Yeah, then don’t do this - problem solved! Maybe I’m wrong and miss some use cases, but I think we should never throw this exception in other cases than after checking that the current coroutine has been cancelled. If someone does this in other cases then they hit themselves in the face.

And please don’t use ChatGPT like this! It will only mislead you.

4 Likes

Ok, maybe one tricky (and honestly really bad) case is when we await() on a coroutine, that coroutine is cancelled and as a result, our coroutine is also cancelled. This is counter-intuitive, unexpected and really bad behavior. If we waited on something and couldn’t get the result, we should fail, not cancel. Hmm… :thinking:

Yeah, as the author suggests, that should probably throw a different exception.

1 Like

@broot the article explains it in details, it is definitely worth giving it a full read.

Yeah, then don’t do this - problem solved

No, it’s not only a problem when you manually throw CancellationException. These exceptions can occur with built-in kotlinx.coroutiines functions:

  • withTimeout throws TimeoutCancellationException (which extends CancellationException)
  • Deferred.await(), ReceiveChannel.receive(), SendChannel.send() all throw CancellationException when the calling coroutine is cancelled (which is OK) BUT ALSO when some other coroutine is cancelled (e.g. the provider of the deferred value or channel value) which is not ok and shouldn’t cancel your calling coroutine silently IMO
1 Like

Yes, I know, I realized this after writing my comment. I missed that initially, because the article is built around the narrative of silent killers and rogue cancellations, and it is very slow in explaining what does the author really mean and why the problem may happen in a real life.

And yes, I think this is really bad. I suspect this is an overlook in coroutines design and it should be fixed one way or another. But that will be hard without introducing backward incompatible changes.

1 Like

Do you have this problem?

Are you doing anything to contain it in your code?