coroutineScope() thread safety?

I haven’t been able to reproduce this yet in an isolated example, however I’m seeing intermittent errors in my app that could be explained if, in the following example, “JOB 2” were printed after “EXIT SCOPE”:

suspend fun main() {
    withContext(Dispatchers.Default) {
        launch job1@{
            this@withContext.launch { println("JOB 2") }
        }
    }
    println("EXIT SCOPE")
}

I expect withContext() to postpone “EXIT SCOPE” until at least job 1 is complete, by which time I expect job 2 will have been added to the scope, further postponing “EXIT SCOPE” until “JOB 2” is complete. Is this guaranteed, however?

In the right multithreaded environment, is it possible for withContext() to end before job 2 is complete?

If this isn’t guaranteed I can instead arrange to call this@job1.launch { println("JOB 2") }, however in my app (where scope is an instance variable) it’s currently more natural as is.

withContext returns as soon as the lambda block completes. If you want to await all launched jobs in a certain scope, consider using coroutineScope instead.

1 Like

If true wouldn’t the following print

  1. Leave withContext()
  2. Delayed

instead of the reverse?

import kotlin.coroutines.EmptyCoroutineContext
suspend fun main() {
    withContext(EmptyCoroutineContext) {
        launch {
            delay(1000L)
            println("Delayed")
        }
    }
    println("Leave withContext()")
}

withContext and coroutineScope don’t resume until all child jobs have finished.

job 2 can finish before or after job 1 finishes, but it will always finish before withContext resumes.

I’ve had problems dealing with CoroutineScope instance variables where I use the wrong scope accidentally:

val myJob = scope.launch {
    someFlow.launchIn(scope) { } // Oops, i mean't "this", not "scope", myJob will finish immediately
}
myJob.invokeOnCompletion { expectSomeFlowCollectionFinished() }

Perhaps you also are running into a similar situation using an unintended scope?