如何为具有动态成员的结构采用 Send 和 Sync(未来不能在线程之间安全地发送)

How to adopt Send and Sync for a struct with a dynamic member (future cannot be sent between threads safely)

考虑以下代码,它使用 async-trait 板条箱使用 async 方法声明特征。

use std::{io::Result, sync::Arc};

use async_trait::async_trait;
use tokio;

// A trait that describes a power source.
trait PowerSource {
    fn supply_power(&self) -> Result<()>;
}

// ElectricMotor implements PowerSource.
struct ElectricMotor {}

impl PowerSource for ElectricMotor {
    fn supply_power(&self) -> Result<()> {
        println!("ElectricMotor::supply_power");
        Ok(())
    }
}

// A trait that describes a vehicle
#[async_trait]
trait Vehicle {
    async fn drive(&self) -> Result<()>;
}

// An automobile has some kind of power source and implements Vehicle
struct Automobile {
    power_source: Arc<dyn PowerSource>,
}

#[async_trait]
impl Vehicle for Automobile {
    async fn drive(&self) -> Result<()> {
        self.power_source.supply_power()?;
        println!("Vehicle::Drive");
        Ok(())
    }
}

#[tokio::main]
async fn main() -> std::io::Result<()> {
    let driver = ElectricMotor {};
    let controller = Automobile {
        power_source: Arc::new(driver),
    };

    controller.drive().await?;

    Ok(())
}

这不会编译并出现错误“未来无法在线程之间安全发送”:

error: future cannot be sent between threads safely
  --> src/main.rs:34:41
   |
34 |       async fn drive(&self) -> Result<()> {
   |  _________________________________________^
35 | |         self.power_source.supply_power()?;
36 | |         println!("Vehicle::Drive");
37 | |         Ok(())
38 | |     }
   | |_____^ future created by async block is not `Send`
   |
   = help: the trait `Sync` is not implemented for `(dyn PowerSource + 'static)`
note: captured value is not `Send`
  --> src/main.rs:34:21
   |
34 |     async fn drive(&self) -> Result<()> {
   |                     ^^^^ has type `&Automobile` which is not `Send`
   = note: required for the cast to the object type `dyn Future<Output = Result<(), std::io::Error>> + Send`

error: future cannot be sent between threads safely
  --> src/main.rs:34:41
   |
34 |       async fn drive(&self) -> Result<()> {
   |  _________________________________________^
35 | |         self.power_source.supply_power()?;
36 | |         println!("Vehicle::Drive");
37 | |         Ok(())
38 | |     }
   | |_____^ future created by async block is not `Send`
   |
   = help: the trait `Send` is not implemented for `(dyn PowerSource + 'static)`
note: captured value is not `Send`
  --> src/main.rs:34:21
   |
34 |     async fn drive(&self) -> Result<()> {
   |                     ^^^^ has type `&Automobile` which is not `Send`
   = note: required for the cast to the object type `dyn Future<Output = Result<(), std::io::Error>> + Send`

如果我理解错误的话,它认为 Automobile 不是 Send 因为 power_source 属性 不是所以它不能创建一个合适的未来。我的理解是 Arc 是线程安全的并且实现了 SendSync,但我对 Rust 并发仍然很陌生,仍然不完全清楚这意味着什么。

我该如何解决这个错误?

您必须修改您的 Automobile 定义:

struct Automobile {
    power_source: Arc<dyn PowerSource>,
}

在 Rust 中,一个类型是 Send 当且仅当它的所有成员都是 Send(除非你手动且不安全地实现 Send)。这同样适用于 Sync。所以假设你的 power_source 不是 Send,那么生成的 impl Future 也不会是 Send.

The way to fix it is to add a Send + Sync requirement for power_source:

struct Automobile {
    power_source: Arc<dyn PowerSource + Send + Sync>,
}

但是为什么 Sync 您可能会问?毕竟编译器只抱怨 Send。它需要 Sync 的原因是因为 Arc<T> implements Send only if T is both Send and Sync

补充阅读: