Sanat Tripathi
05/17/2022, 8:45 PMsuspendCancellableCoroutine
and Mutex
suspend fun awaitCallback(): T = suspendCancellableCoroutine { continuation ->
val callback = object : Callback { // Implementation of some callback interface
override fun onCompleted(value: T) {
// Resume coroutine with a value provided by the callback
continuation.resume(value)
}
override fun onApiError(cause: Throwable) {
// Resume coroutine with an exception provided by the callback
continuation.resumeWithException(cause)
}
}
// Register callback with an API
api.register(callback)
// Remove callback on cancellation
continuation.invokeOnCancellation { api.unregister(callback) }
// At this point the coroutine is suspended by suspendCancellableCoroutine until callback fires
}
suspend fun execute() {
val mutex = Mutex(false)
mutex.lock()
try {
awaitCallback()
} catch(e: Throwable) {
throw e
} finally {
mutex.unlock()
}
}
In the above setup, the moment suspension happens at suspendCancellableCoroutine
mutex in execute
method gets unlocked part of the finally
blockmkrussel
05/17/2022, 8:55 PMSanat Tripathi
05/17/2022, 8:59 PMwithLock
API as well but this is so legacy code that im working with atm.
And im actually trying to figure out why does the unlock
get called right after the suspension happens inside suspendCancellableCoroutine
continuation.resumeX
apis to get called and only then go to finally blockmkrussel
05/17/2022, 9:02 PMawaitCallback
does return on the JVM and then execture
gets called again jumping to the correct continuation point. Not sure how finally blocks behave with that.withLock
looks like what you have there, except without the catch
block.Mutex
in the execute
function?Nick Allen
05/18/2022, 12:32 AMIn the above setup, the moment suspension happens atsuspendCancellableCoroutine
mutex inThere's only one coroutine in the snippet. Pretty sure all that code will run synchronously so it's not clear what you mean.method gets unlocked part of theexecute
block (edited)finally
And im actually trying to figure out why does theget called right after the suspension happens insideunlock
suspendCancellableCoroutine
I was hoping that it would wait forThat's how it works so again, not sure what you mean. Are you sure you aren't seeing executions for multiple concurrent coroutines or something. Also, if register callsapis to get called and only then go to finally blockcontinuation.resumeX
onCompleted
, directly then nothing will suspend. Maybe a https://play.kotlinlang.org/ sample with `println`s would help explain what you are seeing and you can post the output you're hoping for.
Also, suspendCancellableCoroutine
is meant for methods that will only invoke the callback once. If that's the case here then nvm, but register
suggests that it's not and you may want to consider callbackFlow { ... }.first()
to avoid errors in case you receive multiple callback invocations.uli
05/21/2022, 6:20 PMonCompleted
, onApiError
, the `catch`block (also logging the exception) and the finally
block.
If this proves your observation, please post the code here.Sanat Tripathi
05/26/2022, 8:49 PM