异步函数:特性`std::marker::Send`没有为`std::sync::MutexGuard<'_,Client>`实现

我在异步中使用递归时遇到了一个奇怪的错误。

我可以clientasync. 但是,如果我do_something再次打电话,它会抱怨std::sync::MutexGuard<'_, Client>没有被发送。我认为它正在尝试发送c到另一个线程。我以为do_something在一个线程中执行,然后do_something(client.clone()).await在另一个线程中执行。我不明白为什么c要从async线程转移到这个新线程。

use std::sync::{Arc, Mutex};
use std::future::Future;
use futures::future::{BoxFuture, FutureExt};

struct Client{
}

impl Client {}

fn do_something<'a>(
        client: Arc<Mutex<Client>>,
) -> BoxFuture<'a, std::result::Result<(), ()>> {
    async move {
        let c = client.lock().unwrap();
        do_something(client.clone()).await;
        Ok(())
    }.boxed()
}

fn main() {
    let c = Arc::new(Mutex::new(Client{}));
    do_something(c.clone());
}

错误:

error: future cannot be sent between threads safely
  --> src/main.rs:17:7
   |
17 |     }.boxed()
   |       ^^^^^ future created by async block is not `Send`
   |
   = help: within `impl futures::Future`, the trait `std::marker::Send` is not implemented for `std::sync::MutexGuard<'_, Client>`
note: future is not `Send` as this value is used across an await
  --> src/main.rs:15:9
   |
14 |         let c = client.lock().unwrap();
   |             - has type `std::sync::MutexGuard<'_, Client>` which is not `Send`
15 |         do_something(client.clone()).await;
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ await occurs here, with `c` maybe used later
16 |         Ok(())
17 |     }.boxed()
   |     - `c` is later dropped here

操场

回答

这里有两个问题,都源于这样一个事实,即标准库Mutex被设计为与常规阻塞代码一起使用,而不是异步代码:

  • 锁定互斥锁会阻塞线程,这通常是您希望在异步代码中避免的,因为它可以阻止其他任务运行。
  • 正如编译器错误中所见,通过锁定它获得的互斥锁不能在线程之间安全地共享,因此无论如何它都不会编译。

这两个问题都可以通过使用Mutex专为异步代码设计的代码来解决。由于您已经在使用futurescrate 中的某些内容,因此您可以使用futures::lock::Mutex, 更改client.lock().unwrap()client.lock().await. 当需要等待而不是阻塞线程时,此版本的锁会将控制权交还给任务执行器,并且还允许在必要时在线程之间共享它。

代码的完整版本看起来像这样 - 然而,它不是很有用,因为你从来没有真正执行返回的未来do_something(注意你没有对返回的未来做任何事情),即使你这样做了,它也会立即递归导致的死锁:

use std::sync::Arc;
use std::future::Future;
use futures::future::{BoxFuture, FutureExt};
use futures::lock::Mutex;

struct Client {}

impl Client {}

fn do_something<'a>(
        client: Arc<Mutex<Client>>,
) -> BoxFuture<'a, std::result::Result<(), ()>> {
    async move {
        let c = client.lock().await;
        do_something(client.clone()).await;
        Ok(())
    }.boxed()
}

fn main() {
    let c = Arc::new(Mutex::new(Client {}));
    do_something(c.clone());
}

操场


以上是异步函数:特性`std::marker::Send`没有为`std::sync::MutexGuard&lt;'_,Client&gt;`实现的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>