Return when either async returns

pub async fn foo() {
  let t1: JoinHandle<...> = ...;
  let t2: JoinHandle<...> = ...;
  t1.await;
  t2.await;
}

This function does not quite have the behavior I want because if t2 finishes, but t1 does not, the function does not return.

How do I say: return if either t1 or t2 finishes ?

I think you're looking for the select! macro

2 Likes

You can do it like this:

let res = tokio::select! {
    res = t1 => res,
    res = t2 => res,
};

If you want to kill the other task that didn't complete first, then do this:

let res = tokio::select! {
    res = &mut t1 => { t2.abort(); res },
    res = &mut t2 => { t1.abort(); res },
};

The value of res will be Ok(the_returned_value_by_the_task) or Err(the_panic) if the task panicked.

1 Like

You might even want to do this:

let res = tokio::select! {
    res = &mut t1 => { t2.abort(); t2.await; res },
    res = &mut t2 => { t1.abort(); t1.await; res },
};

This will make the code wait until the cancelled task's destructor has finished running, whereas the destructor might run after you return from the function with the other code.

1 Like