https://kotlinlang.org logo
#coroutines
Title
# coroutines
s

spand

10/10/2018, 9:03 AM
Say I have a
val scope = GlobalScope + Job()
that is no longer active. If I call
scope.launch
the new coroutine will never get a chance to execute but caller of
launch
is oblivious to this. Would it not make more sense have a fail fast behaviour akin to
Executor.execute
that throws
RejectedExecutionException
in a similar situation ?
e

elizarov

10/10/2018, 10:40 AM
That would lead to a race. So, when you cancel a coroutine that is trying to start you child you’d sometimes get this exception, and sometimes not.
You should use structured concurrency. You should not start child from a random place in your code, but only from a parent code. So, if the parent job is already cancelled, it should not be trying to start more children
(it should be shutting down instead)
g

gildor

10/10/2018, 10:42 AM
You also can implement such scope yourself. Just check that job is not cancelled on each call of coroutineContext. I didn’t try, maybe there are some pitfalls
s

spand

10/10/2018, 10:54 AM
Cant see why the race is a problem.
ConcurrentModificationErrors
and similar fail fast checks are not guaranteed either.
The calls to
launch
occur outside of the parent as network events come in. Not sure how to change that.
e

elizarov

10/10/2018, 11:04 AM
CME
is thrown when you have bug in your code. With a proposed
REE
you’ll get it from time to time from a perfectly good code without any bug. That is not Ok
It simply means you are launching in wrong scope. Use structured concurrency. Don’t launch child outside of parent.
s

spand

10/10/2018, 11:13 AM
I can see how it would be a poor fit if calls to
launch
should only happen from inside a parent.
I guess I need to look into how to avoid this need I seem to have then
e

elizarov

10/10/2018, 11:15 AM
If you are launching from parent, then your bases are covered. If you cannot launch, it means you (parent) is already cancelled and should be shutting down
Now, there is one corner-case:
Copy code
val resource = openSomeResource()
launch { // child will close resource
    try { ... } finally { resource.close }
}
You cannot afford this child not to start, or you loose a resource.
To fix that, use
launch(start = CoroutineStart.ATOMIC)
.
s

spand

10/10/2018, 11:22 AM
Thanks for your time. Good to know about
ATOMIC
. I have something similar myself.
The Activity class in https://github.com/Kotlin/kotlinx.coroutines/blob/master/docs/coroutine-context-and-dispatchers.md#cancellation-via-explicit-job is similar to what I am doing currently. The difference is that I would want an exception synchronously if
doSomething()
is either called before
create()
, after
destroy()
or if the
job
is cancelled due to a coding error. Seems like a simple requirement but how would one extend the example to handle that ?
e

elizarov

10/10/2018, 2:11 PM
We cannot support that, unfortunately
You’ll have to use your own functions that throw the corresponding exceptions to achieve this behavior
s

spand

10/10/2018, 2:21 PM
ie. blocking the thread until I get a signal from the launched block that it started executing OR the returned job from launch is cancelled ? (assuming the returned job from
launch
isnt synchronously set to
isCancelled
)
e

elizarov

10/10/2018, 2:48 PM
Whatever your use-cases calls for.
2 Views