uhe
02/16/2018, 9:49 AMsuspendAtomicCancellableCoroutine
and suspendCancellableCoroutine
?Jonathan
02/16/2018, 9:59 AMcont.resume()
, while the other may be cancelled even after calling cont.resume()
.uhe
02/16/2018, 12:30 PMJonathan
02/16/2018, 12:52 PMval atomicValue = AtomicInteger(0)
var value = 0
fun usage() {
// This doesn't ensure that the value printed is the one after increment
// Because another thread could have changed the value in between (it is not atomic)
++value
println(value)
// This ensure to print the correct value after increment (it is atomic)
println(atomicValue.incrementAndGet())
}
I think it is the same for coroutines cancellation
suspend fun atomicCancellableFct() =
suspendAtomicCancellableCoroutine<Unit> { it.resume(Unit) }
suspend fun cancellableFct() =
suspendCancellableCoroutine<Unit> { it.resume(Unit) }
suspend fun usage() {
// This call may throw a CancellationException, even if the actual content has been resumed
// This is because cancel may be called during the resume process
cancellableFct()
// This ensure that either
// * the content is resumed but doesn't throw any CancellationException
// * the content is NOT resumed and throw a CancellationException
// But never both, because it will be *atomic*
atomicCancellableFct()
}
And about how to choose, for me it is the same as choosing between Int
and AtomicInteger
.
I will always use non-atomic operations unless I am implementing a very specific case that does need to use atomicity.uhe
02/16/2018, 1:02 PMuhe
02/16/2018, 1:03 PMJonathan
02/16/2018, 1:07 PMlock()
of Mutex
. The cancellation of this function is atomic, and the reason is quite easy to understand I think. We need to be sure that either the function throw a CancellationException
OR a lock has been acquired, but not both. If the function would succeed to acquire a lock AND throw an exception, one could end up with deadlocks very difficult to debug.Jonathan
02/16/2018, 1:15 PMdelay()
cancellation is not atomic, because in case of cancellation, we don't care if the delay already resumed or not.
Mutex.lock()
cancellation is atomic. Because in case of cancellation, if a lock has been acquired, we have to call Mutex.unlock()
to avoid deadlocks.Jonathan
02/16/2018, 1:25 PMsuspendAtomicCancellableCoroutine
, otherwise, use suspendCancellableCoroutine
uhe
02/16/2018, 1:32 PMuhe
02/16/2018, 1:44 PMuli
02/16/2018, 7:04 PM