Why "future is not `Send` as this value is used across an await" and how to fix?

I had to recursively call my async function but got error that I could not understand and don't know how to fix:

use core::future::Future;
use futures::future::{BoxFuture, FutureExt};

async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
}

fn foo(tx: std::sync::mpsc::Sender<i32>) -> BoxFuture<'static, ()>{
    async move {
        baz(|| async{
            foo(tx.clone());
        }).await;
    }.boxed()
}

fn bar(_s: impl Future + Send) {
}

fn main() {
    let (tx, _rx) = std::sync::mpsc::channel();
    bar(foo(tx));
}

Error:

   Compiling playground v0.0.1 (/playground)
error: future cannot be sent between threads safely
  --> src/main.rs:12:7
   |
12 |     }.boxed()
   |       ^^^^^ future returned by `foo` is not `Send`
   |
   = help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Sender<i32>`
note: future is not `Send` as this value is used across an await
  --> src/main.rs:9:9
   |
9  |            baz(|| async{
   |  __________^___-
   | | _________|
   | ||
10 | ||             foo(tx.clone());
11 | ||         }).await;
   | ||         -      ^- `|| async{
            foo(tx.clone());
        }` is later dropped here
   | ||_________|______|
   | |__________|      await occurs here, with `|| async{
            foo(tx.clone());
        }` maybe used later
   |            has type `[closure@src/main.rs:9:13: 11:10 tx:&std::sync::mpsc::Sender<i32>]`

error: aborting due to previous error

error: could not compile `playground`.

To learn more, run the command again with --verbose.

What I don't understand is

note: future is not `Send` as this value is used across an await

There is only one await in foo, why does the error message says the value is used across an await? Does "across" mean something like this?

let mut a = 1;
some_func().await;
a = 2;
some_func().await;
a = 3;  // a used across multiple awaits

Help in understanding the error message and how to fix is greatly appreciated!

    async move {
        baz(move || {
            let txc = tx.clone();
            async /* move */ {
                foo(txc);
        }}).await;
    }.boxed()

The "across" is due to impl FnMut(). must be callable multiple times so references will be made.

Alternative fix is change to impl FnOnce() and add the move.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.