-
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
withContext from inside a cancelled coroutine should not be executed #962
Comments
This happens so by design. The reason for such behavior is to enable |
@elizarov Couldn't a special case be added for |
@elizarov If
|
Unfortunately, the ship might have sailed for this particular decision, but I do see the problem it causes. The way it was originally designed is that In the experimental version we also had an optional The reason your third block is not executed, is because I do not have easy solution out of this, but to provide a separate |
I've investigated what happens if we change this behavior and check for cancellation on the entrance to |
* Immediately check is the new context is cancelled and throw CancellationException as needed * Properly explain cancellation behavior in documentation Fixes #962
While we talk about the cancelation semantics of withContext, an issue came up on slack yesterday: The issue is, that canceling a coroutine at the end of a
Which outputs:
|
@uluckas Having this YouTrack issue resolved would allow to avoid the resource leak demonstrated above the following way: import kotlinx.coroutines.*
class Resource {
init {
println("Initializing resource")
Thread.sleep(1000)
println("Slow initialization done")
}
fun release() {
println("Released")
}
}
suspend fun initWithContext() {
val resource: Resource
try {
withContext(Dispatchers.Default) {
resource = Resource()
}
} finally {
resource.release()
}
}
fun main() = runBlocking {
val initJob = launch {
initWithContext()
}
yield()
initJob.cancel()
}
EDIT: My bad, even with contracts for suspend functions, this needs to be a |
@uluckas
This is also related to a bunch of other problems (see #279 and #845). |
@elizarov I see the problem that |
@Dougrinch this is indeed the case. Let's move discussion on overriding Job in the context into #1001 |
Thanks @elizarov for the update |
Consider the following example:
Currently this outputs the following:
That is, the second
withContext
is executed despite the fact the parent coroutine has already been cancelled by the time the child is created.This behavior seems a bit counterintuitive, and it is also inconsistent with how a similar example using a
Default
coroutine dispatcher works:Output:
Note that
async { ... }.await()
works fine with either of the dispatchers:Output:
My suggestion is to make the behavior of child coroutines created using different builders consistent so that a child doesn't start executing if a parent has already been cancelled by the time the child is created.
BTW IDEA has an quick fix suggesting to replace
async { ... }.await()
withwithContext
, which now happens to change the semantics w.r.t. cancellation when a child uses the same dispatcher.The text was updated successfully, but these errors were encountered: