Async - waiting for a condition

Hi,

I want to create a future that resolves when a certain condition becomes true.
I could be using a Condvar but I don't really need a mutex, ideally I would like to "set an event" and complete the future.

My approach so far

fn wait_popup<'a>(condition: &'a bool) -> impl Future<Output = ()> + 'a {
    WaitPopup{condition}
}

struct WaitPopup<'a> {
    condition: &'a bool
}

impl<'a> Future for WaitPopup<'a> {
    type Output = ();

    fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll<Self::Output> {
        if *self.condition == true {
            Poll::Pending
        }
        else {
            Poll::Ready(())
        }
    }
}

This is working, but I don't know if I'm reinventing the wheel and there is already something I could use.
Any suggestion of how is this problem commonly solved?
Thanks!

Just having a condition you can check is not enough to create a future. You all need a way to notify when the check becomes true. When you return Pending, that is actually a promise that you will emit a wakeup to the waker in the Context argument once you want to be polled again — otherwise the runtime will never poll the future again.

Consider using a channel or tokio::sync::Notify or one of the other things in tokio::sync.

Expanding on alice's answer, you can use Context::waker to get a reference to a Waker you can use to signal to the executor that your Future is ready. Note that you can clone it and store/send it somewhere else where you'll know when the condition will become true.

On a sidenote, I don't see how your current code is working. If condition is false when WaitPopup is created then it will never be able to point to true because that would be UB.

Thanks for the suggestion @SkiFire13 . I need to explore the Context and Waker API's. For now I think I'll use Notify from Tokio as alice suggested.

And you're right, I tested my code on true/false condition state but I never got to set it because I need to change a few things to use RwMutex in order to be able to use different tasks. I supposed that when a type implemented a future and it was polled once, the runtime would take care of polling it again - which after reading a bit on what is this context argument that I'm not using I understand that I couldn't be more wrong by imagining it would be polled in a loop or something.

Thanks for pointing me on the right direction!

An important piece here is that "the runtime" is just more rust code. Nothing is going to happen without you telling it to.

you could write a runtime that polls every future once a second, and then your code would work, but that would also result in a lot of unnecessary work. The design of rusts async system is that executors shouldn't have to do any work unless a future wakes them.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.