Wait in task until parent has returned

Hi there,
I'm facing an issue that I must wait in an async::task until the function that spawned me has returned.
Basically an async defer.

now I quickly already conjured up this monstrosity, but I figured there may be some better solution already. Please help me find that.

struct DropGuard(event_listener::Event);

impl DropGuard {
    fn create() -> (DropGuard, event_listener::EventListener) {
        let event = event_listener::Event::new();
        let listener = event.listen();
        (DropGuard(event), listener)
    }
}

impl Drop for DropGuard {
    fn drop(&mut self) {
        log::trace!("dropping guard");
        self.0.notify(1);
    }
}

async fn that_must_return_before_the_task_runs() {
    let (drop_guard, has_returned) = DropGuard::create();
    task::spawn(async move {
        has_returned.await;
        // now we can go on
    });
}

Thank you

Given that in the example code at hand one could just as well (with essentially equivalent effect) do the task::spawn call at the end of the that_must_return_before_the_task_runs function[1], I think you need to give us more context as to why you want to achieve what you’re describing here.


  1. which, given the minimal/minimized(?) nature of the code at hand is already what is happening anyways, so the whole thing that’s done here becomes a bit pointless… ↩︎

:thinking: Maybe it’s about making sure the code runs, too, in a panicking case? Well, I suppose it should be possible (and slightly less convoluted) to use a normal non-async defer approach, and execute the task::spawn call itself only in the deferred code?

absolutely true!

I'm writing a zbus server application and my method actually being wrapped and it's return value is sent back to the client. I need to make sure the return value has been sent before my sub-task sends a subsequent signal to the client.

So my example looks more like this

async fn handle_notification(&mut self) {
    self.current_id = self.current_id+1;
    let (drop_guard, has_returned) = DropGuard::create();
    task::spawn(async move {
        has_returned.await;
        // now we can assume that the client has received my response
        // and I can send them messages that refer to `current_id`
    });
    Ok(self.current_id)
}

I still don’t see how that code is particularly sensible. The task::spawn was already the last thing that happens in handle_notification before the destructors of local variables are run. Making the spawned task wait for drop_guard to be dropped is going to make it wait essentially no longer at all, since dropping drop_guard is the very next thing that happens after the task::spawn call.

I'm not saying my solution is good enough. I want to make sure that what ever code calls me get's my return value before I continue with my sub-task.

Well, even once the method returned, the value is not yet sent. Really, the caller must somehow indicate the action that needs to happen before the sub-task is supposed to start.

So… maybe a callback works?

// feel free to fill in the gaps
// e.g. whether or not the callback should get `Result`, or just not called
// in case of error; and whether or not the callback should be able to
// do some `async` operations
async fn handle_notification(&mut self, callback: impl FnOnce(…)) {
    self.current_id = self.current_id+1;
    callback(self.current_id) // e.g. sending the id to the client (or
    // anything else that should happen *before* the below task
    // is started it expected to be done in the callback provided by the caller


    // now we can assume that the client has received my response
    // and I can send them messages that refer to `current_id`
    task::spawn(async move {
        …
    });
}

Alternatively, instead of accepting a callback, handle_notification could also return both the id and some kind of handle to start the sub-task after the id was taken care of (and e.g. sent off).

1 Like

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.