如何从 Arc<Mutex 借用可变引用<T>>并对其调用异步成员函数?



我有一个简单的结构和一个如下所示的实现。

#[derive(Debug)]
struct MyStruct {
data: u64,
}
impl MyStruct {
async fn something_async(&mut self) -> Result<(), Box<dyn Error>> {
self.data += 1;
Ok(())
}
}

我想使用智能指针和互斥体在堆上使用MyStruct,这样我就可以在多个线程中使用它。

然而,当我尝试调用名为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);
});

我得到以下错误:

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`

我假设编译器不喜欢我在await上保持MutexGuard,所以我尝试了这个:

let fut = {
let mut s = ptr.lock().unwrap();
s.something_async()
};
fut.await.unwrap();

但当然,它抱怨未来比可变参考寿命不够长:

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

如何对封装在Arc<Mutex<T>>中的对象调用异步方法?

使MyStruct可复制。

#[derive(Debug, Copy, Clone)]
struct MyStruct {
data: u64,
}
impl MyStruct {
async fn something_async(&mut self) -> Result<(), Box<dyn Error>> {
self.data += 1;
Ok(())
}
}
#[tokio::main]
async fn main() {
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);
});
}

最新更新