``` fun main() { runBlocking { val job...
# coroutines
t
Copy code
fun main() {
    runBlocking {
        val job = launch {
            suspendCoroutine<Unit> {}
        }

        yield()
        job.cancel()
        println("goodbye")
    }
    println("exit")
}
prints
Copy code
goodbye
and then hangs forever. Does anybody know why this happens? When removing the
yield()
it just works as expected.
s
Copy code
fun main(argv: Array<String>) {

        runBlocking {
            val job = launch {
                suspendCoroutine<Unit> { continuation ->
                    continuation.resume(Unit)
                    
                }
            }

         yield()
            job.cancel()
            println("goodbye")
        }
        println("exit")


}
in your original example suspendCorountione wasn't created before the job was cancelled
s
Hmmm... All the runBlocking's child routines end (one by being cancelled) and runBlocking should too... What happens if you put a Thread.sleep(...) or delay(...) in the suspendedCoroutine (but still without calling 'resume')?
s
because the dispatcher of runBlocking run everything on the same thread
when you added yield it was able to create it
but suspendCorotuine didnt finish because you didnt resume the continuation
r
@sitepodmatt note: you can use the item just below “Unread messages” on the top left of Slack to view threads in full width
🕺 1
🎉 1
s
so the the runBlocking waits for a children to finish which it never would
t
But the coroutine should be cancelled, even if it is suspended. My real usecase is more like this:
Copy code
suspendCoroutine<Unit> { continuation ->
    performPotentiallyNeverEndingStuff(callback = {
        continuation.resume(Unit)
    }) 
}
Which effectively has the same problem
s
you need a suspendCancellableCoroutine
Copy code
un main(argv: Array<String>) {

        runBlocking {
            val job = launch {
                suspendCancellableCoroutine<Unit> { }
            }

            yield()
            job.cancel()
            println("goodbye")
        }
        println("exit")

}
💯 1
t
Nice, this is what I was looking for. Thanks!
s
Still though; why did the original code then work when it has that 'yield()' call?
t
It was the other way around: It did not work when the yield was invoked. And without the yield, the
runBlocking
body was never suspended, so the job did not even start executing before it was cancelled again. So the non-cancellable
suspendCoroutine
did not start and didn't block the cancellation of the job.
Copy code
fun main(argv: Array<String>) {

    runBlocking {
        val job = launch(Dispatchers.Default) {
            suspendCoroutine<Unit> { }
        }
        job.cancel()
        println("goodbye")
    }
    println("exit")
}
This sometimes blocks and sometimes not, because if the default dispatcher manages to execute
suspendCoroutine
before the
runBlocking
finishes, the job is non-cancellable again.
s
That would explain it :) Still, I think it should not matter whether the dispatcher managed to execute 'suspendCoroutine' or not early on.... The 'launch' is called, it is not lazy, and the job should be considered either always running or always not running, not sometimes the one and sometimes the other....