Reputation: 4042
After reading Kotlin documentation, I came up with the following code (which is not working - see below) to repeat a function call until it returns true, or timeout is reached.
I want to pause execution until this code block reaches timeout or success - it is not supposed to execute asynchronously.
Log.d(TAG, "This is the last line to be logged")
runBlocking {
Log.d(TAG, "this line is never logged")
try {
withTimeout(timeoutMsL) {
while ((isActive) && (!success)) {
success = doSomething()
}
}
}
catch (ex: TimeoutCancellationException) {
Log.d(TAG, "this line is never logged either")
doSomethingElse()
}
}
timeoutMsL
is a Long
with typical value 50 ms.
This code is called from C++ over the JNI. When I run it
I have read that runBlocking
should be avoided, but also you have to call withTimeout
from an existing coroutine.
If I use a normal coroutine, execution of the calling function will continue before timeout /success is reached - I need to prevent this from happening.
How should this be coded in Kotlin?
Upvotes: 1
Views: 1954
Reputation: 25603
Your problem probably lies in doSomething()
. Kotlin's coroutine implementation relies a lot on cooperative execution where child coroutines check flags to see if they have been cancelled (as withTimeout()
would do). This would mean the outer coroutines will pause until they confirm the child coroutines have ended, blocking the entire function.
if doSomething
never suspends and never checks if it is still active it will just run until completion regardless of the external situation.
To fix this, there are two options:
doSomething()
a suspend
function and regularly suspend with either yield()
or ensureActive()
to respond to cancellation.withContext(Dispatchers.IO)
.Upvotes: 1