Skip to content

runBlocking with Android's Main.immediate scheduler locks with other nested contexts #2448

Open
@dlew

Description

@dlew

I've been trying to figure out why this code freezes on Android (when started on the main thread):

runBlocking {
  Log.i("test", "start runBlocking")
  withContext(Dispatchers.Main.immediate) {
    Log.i("test", "start Main.immediate context")
    withContext(Dispatchers.IO) {
      Log.i("test", "running IO context") // Prints
    }
    Log.i("test", "end Main.immediate context") // Never prints
  }
  Log.i("test", "end runBlocking") // Never prints
}

The inner context has to be something like Dispatchers.Default or Dispatchers.IO.

I've been able to track down where the code freezes: BlockingCoroutine.joinBlocking() eventually calls parkNanos(this, Long.MAX) and thus the code just stops. I don't understand coroutines well enough to understand how it got into this state, though.

This came up because it's easy to accidentally run into this situation when calling suspending functions that are using their own withContext() calls. E.g., you call runBlocking { someSuspendingFunction() }, not knowing that you're going to end up inside Main.immediate and then IO (resulting in a freeze).

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions