Cannot use async function in thread: `Future created by async block is not `Send`.`

I simplified my code to the sample below:

struct Ptr {
    ptr: *mut i32,
}

unsafe impl Send for Ptr { }

impl Ptr {
    fn f1(&self) {
        println!("Hi there");
    }
}

struct Wrapper {
    ptr: Ptr,
}

impl Wrapper {
    async fn async_fn(&self) -> Option<()> {
        Some(())
    }
}

#[tokio::main]
async fn main() {
    let ptr = Ptr{ ptr: &mut 12 as &mut i32 };
    let wrapper = Wrapper { ptr };

    tokio::spawn(async move {
        loop {
            wrapper.async_fn().await;
        }
    });
}

I want to do some FFI on a simple c library that provides a pointer that can be safely sent between threads. So, I use unsafe impl Send for T on that type, say Ptr here.

Then, the Ptr is wrapped in another Wrapper on which an async function is implemented that produces a value when it is polled.

However, when this async function is polled in a tokio::spawn thread, the compiler strikes.

error: future cannot be sent between threads safely
   --> src/main.rs:28:5
    |
28  |     tokio::spawn(async move {
    |     ^^^^^^^^^^^^ future created by async block is not `Send`
    |
    = help: within `Wrapper`, the trait `Sync` is not implemented for `*mut i32`
note: future is not `Send` as this value is used across an await
   --> src/main.rs:30:13
    |
30  |             wrapper.async_fn().await;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ first, await occurs here, with `wrapper` maybe used later...
note: `wrapper` is later dropped here
   --> src/main.rs:30:37
    |
30  |             wrapper.async_fn().await;
    |             -------                 ^
    |             |
    |             has type `&Wrapper` which is not `Send`
help: consider moving this into a `let` binding to create a shorter lived borrow
   --> src/main.rs:30:13
    |
30  |             wrapper.async_fn().await;
    |             ^^^^^^^^^^^^^^^^^^
note: required by a bound in `tokio::spawn`
   --> /home/doug/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.14.0/src/task/spawn.rs:127:21
    |
127 |         T: Future + Send + 'static,
    |                     ^^^^ required by this bound in `tokio::spawn`

error: could not compile `send_and_sync` due to previous error

How did this happen? How could I fix it?

It's because the struct currently doesn't implement Sync. The meaning of Sync is that immutable references are Send, and your async_fn method has an immutable reference to your pointer.

Ok, I know &T is Send only when T is Sync. But to my situation, the raw pointer cannot be Sync which means it cannot be accessed by multiple threads same time.

For such a scenario, how could I fix it?

Doesn't this mean that Wrapper::async_fn must take &mut self or self, not &self? Otherwise, you would be able to spawn multiple tasks with references to the same Wrapper (correspondingly, the same Pointer), which may very well run on different threads.

1 Like

You solved my problem...

I indeed don't realize the distinction between the &mut T and the &T in the context of Send.

Are there any good articles or docs that dive into this hard shell?

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.