-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Nested runBlocking
deadlocks when a task depends on the nested runBlocking
itself
#3982
Comments
runBlocking
deadlock when a task runBlocking
deadlock when a task depends on the nested runBlocking
itself
runBlocking
deadlock when a task depends on the nested runBlocking
itselfrunBlocking
deadlocks when a task depends on the nested runBlocking
itself
A simplified reproducer: fun main() {
runBlocking {
val job = launch {
runBlocking {
}
}
launch {
runBlocking {
job.join()
}
}
}
} |
Right now, the code I show above hangs. If we disable work stealing and let the thread do its thing inside fun main() {
runBlocking {
val job = launch {
yield() // new thing
runBlocking {
}
}
launch {
runBlocking {
job.join()
}
}
}
} Right now, this code passes just fine: the In fact, in your case, just swapping the What I'm getting from this is, with |
Basically, yes. |
The important thing here is a conceptual problem: should |
I did hit this edge case in one of my projects and it was difficult to debug based on just thread and coroutine dumps. Some coroutines were just stuck in CREATED state forever. Run this with a dispatcher using 4 threads and you have a deadlock. Unfortunately, the main reason runBlocking is needed is to provide asynchronous resources within class initializers which are not suspending. Solution for me was to remove thread limit, then there is always a new thread available to unpause the coroutine and for other threads to unblock as a result. Alternatively, the design for task- stealing executor is quite simple and maybe will be in Kotlin some day? |
What do we have now?
The following deadlocks because nested
runBlocking
tries to process tasks from the outerrunBlocking
, and one of the tasks actually depends on the completion of the nestedrunBlocking
:What should be instead?
runBlocking
should not steal tasks from outerrunBlocking
.Alternatively, please provide an API to make
runBlocking
not steal tasks. It may be a boolean, or a special coroutine context element. Currently we have to use internals.Why?
Because otherwise it deadlocks.
Notes
Originally, the "stealing" was added to fix a very specific use-case #860.
I believe that if nested
runBlocking
"steals" tasks while being inside a limited dispatcher, then this stealing logic should apply to all limited dispatchers, i.e.runBlocking
on a thread insideDispatchers.Default
should steal tasks fromDispatchers.Default
(#3439). If that's not possible for any reason, then nestedrunBlocking
should not steal tasks from the outerrunBlocking
for the very same reason whatever it might be.The text was updated successfully, but these errors were encountered: