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 suspendCancellableCoroutineSanat Tripathi
05/17/2022, 9:00 PMcontinuation.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.mkrussel
05/17/2022, 9:08 PMwithLock looks like what you have there, except without the catch block.mkrussel
05/17/2022, 9:08 PMMutex 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 theexecuteblock (edited)finally
And im actually trying to figure out why does theget called right after the suspension happens insideunlocksuspendCancellableCoroutine
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