Is there a coroutine equvivalence of Java's <Condi...
# coroutines
m
Is there a coroutine equvivalence of Java's Condition (or wait/notify)? I want to suspend a coroutine until notified or a specified timeout has passed.
s
You could join() a Job, and wrap the whole thing in withTimeout()
k
It could also be another primitive, like
StateFlow<Boolean>
1
To emulate a condition variable you could have the following:
Copy code
val stateFlow = StateFlow<Boolean>(false)

// notify
stateFlow.value = true

// await notification by suspending until the stateflow's value is true
withTimeout(timeout) { stateFlow.first { it } }
This has some edge cases, namely the StateFlow’s value switching back and forth between false and true quickly. If you want the exact same semantics as
Condition
you might be able to build one fairly easily which wraps a channel.
p
Doesn't
first
throw an exception if no value has been emitted?
k
First will suspend until its predicate is satisfied, and on a stateflow that means it will suspend indefinitely until a
true
value is emitted.
p
Humm I see. Documentation is very confusing 😞. I think some sample code explaining this should be in the documentation. It clearly says
Copy code
Throws NoSuchElementException if the flow was empty.
The key question here is, what determines a flow is empty. Sorry for deviating a bit from the original question 🙂
k
A flow is considered empty if it completes without ever having emitted an element
A stateflow can never by empty by nature of having a state value, and also this operator will never throw NSE on it because stateflows and shared flows never complete
For example,
flowOf()
and
flow { }
are both considered to be empty because they complete and never emit anything
p
I am taking a screenshot and saving it for my records. Thanks 🙏 Where could I file a ticket to have the flow emptyness explanation added to the docs
I see in other flow operators docs the same "flow empty" terminology is used without further explanation of what it means
k
I imagine you’ll want to file an issue on Github, but I’m not a maintainer so I can’t say for sure 🙂
The correct place to document this might be on the function emptyFlow? I’m not sure. https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/empty-flow.html
It might also be worth having this documented on the
Flow
interface
👍 1
r
You could also use a Mutex. The call in the coroutine would be to
lock
(or a block of code in
withLock
) wrapped in
withTimeout
. Another approach would be to use a Channel. Wrap
receive
in
withTimeout
. If you need to wait on multiple conditions you can combine awaiting on jobs, or channels, or deferreds, or a timeout, with select.
k
I don’t think mutex models this correctly. You can potentially have many awaiters, and without acquiring the lock, you can’t simply wait for the mutex to be unlocked, right?
r
OP didn't say he had multiple coroutines waiting on the condition. He said "a coroutine". So to model it with a mutex you simply pass in an already locked mutex to the coroutine that needs to await.
k
Oh, fair, sorry. You’re right.
r
Another option is
CompletableDeferred
. The coroutine calls
await
surrounded by
withTimeout
. This can also be combined with
select
for multiple conditions. It can be completed with
Unit
, doesn't have to be a value (but could be).
1