I have a simple struct and an implementation that looks like this.
#[derive(Debug)]
struct MyStruct {
data: u64,
}
impl MyStruct {
async fn something_async(&mut self) -> Result<(), Box<dyn Error>> {
self.data += 1;
Ok(())
}
}
I want to use MyStruct on the heap using a smart pointer and a mutex so that I can use it from multiple threads.
However, when I try to call the async function called something_async()...
tokio::spawn(async move {
let ptr = Arc::new(Mutex::new(MyStruct { data: 1 }));
let mut s = ptr.lock().unwrap();
s.something_async().await.unwrap();
println!("{:?}", s);
});
...I get the following error:
error: future cannot be sent between threads safely
--> src/main.rs:18:5
|
18 | tokio::spawn(async move {
| ^^^^^^^^^^^^ future created by async block is not `Send`
|
= help: within `impl Future<Output = [async output]>`, the trait `Send` is not implemented for `std::sync::MutexGuard<'_, MyStruct>`
note: future is not `Send` as this value is used across an await
--> src/main.rs:21:9
|
20 | let mut s = ptr.lock().unwrap();
| ----- has type `std::sync::MutexGuard<'_, MyStruct>` which is not `Send`
21 | s.something_async().await.unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^ await occurs here, with `mut s` maybe used later
22 | println!("{:?}", s);
23 | });
| - `mut s` is later dropped here
note: required by a bound in `tokio::spawn`
--> /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.16.1/src/task/spawn.rs:127:21
|
127 | T: Future + Send + 'static,
| ^^^^ required by this bound in `tokio::spawn`
I am assuming that the compiler does not like me keeping a MutexGuard held across an await, so I tried this instead:
let fut = {
let mut s = ptr.lock().unwrap();
s.something_async()
};
fut.await.unwrap();
But of course then it complains about the Future outliving the mutable reference not living long enough:
error[E0597]: `s` does not live long enough
--> src/main.rs:22:13
|
20 | let fut = {
| --- borrow later stored here
21 | let mut s = ptr.lock().unwrap();
22 | s.something_async()
| ^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
23 | };
| - `s` dropped here while still borrowed
How do I call an async method on an object wrapped in an Arc<Mutex<T>>?