【问题标题】:Sharing a struct with trait objects as properties across threads跨线程共享具有特征对象的结构作为属性
【发布时间】:2018-06-23 15:04:09
【问题描述】:

我有下面的代码。使用注释掉的部分,它正在工作。当我取消注释部分时,它不再编译。

如何调整注释部分以使其工作,即我想让线程同时访问表达式树。

当我尝试它时,编译器以关于线程安全性的错误开始。

我阅读了 Rust 书籍并且了解 C/C++,但还没有完全理解 Rust 类型系统和语义。

use std::thread;
use std::sync::Arc;

pub trait Expr {
    fn run(&self) -> i32;
}

pub struct ConstantExpr {
    n: i32,
}

impl ConstantExpr {
    pub fn new(n: i32) -> Self {
        Self { n }
    }
}

impl Expr for ConstantExpr {
    fn run(&self) -> i32 {
        self.n
    }
}

pub struct AddExpr {
    expr1: Box<Expr>,
    expr2: Box<Expr>,
}

impl AddExpr {
    pub fn new(expr1: Box<Expr>, expr2: Box<Expr>) -> Self {
        Self { expr1, expr2 }
    }
}

impl Expr for AddExpr {
    fn run(&self) -> i32 {
        self.expr1.run() + self.expr2.run()
    }
}

struct Container {
    x: i32,
    cached_expr: Arc<Expr>,
}

impl Container {
    fn new() -> Self {
        Self {
            x: 0,
            cached_expr: Arc::new(AddExpr::new(
                Box::new(ConstantExpr::new(10)),
                Box::new(ConstantExpr::new(1)),
            )),
        }
    }
}

fn main() {
    let container = Arc::new(Container::new());

    let container1 = Arc::clone(&container);

    /*
    let thread1 = thread::spawn(move || {
        println!("thread1: {}", container1.x);
        println!("thread1: {}", container1.cached_expr.run());
    });
    */

    println!("main: {}", container.x);
    println!("main: {}", container.cached_expr.run());

    //thread1.join().unwrap();
}

错误:

error[E0277]: the trait bound `Expr + 'static: std::marker::Send` is not satisfied
  --> src/main.rs:64:19
   |
64 |     let thread1 = thread::spawn(move || {
   |                   ^^^^^^^^^^^^^ `Expr + 'static` cannot be sent between threads safely
   |
   = help: the trait `std::marker::Send` is not implemented for `Expr + 'static`
   = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<Expr + 'static>`
   = note: required because it appears within the type `Container`
   = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<Container>`
   = note: required because it appears within the type `[closure@src/main.rs:64:33: 67:6 container1:std::sync::Arc<Container>]`
   = note: required by `std::thread::spawn`

error[E0277]: the trait bound `Expr + 'static: std::marker::Sync` is not satisfied
  --> src/main.rs:64:19
   |
64 |     let thread1 = thread::spawn(move || {
   |                   ^^^^^^^^^^^^^ `Expr + 'static` cannot be shared between threads safely
   |
   = help: the trait `std::marker::Sync` is not implemented for `Expr + 'static`
   = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<Expr + 'static>`
   = note: required because it appears within the type `Container`
   = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<Container>`
   = note: required because it appears within the type `[closure@src/main.rs:64:33: 67:6 container1:std::sync::Arc<Container>]`
   = note: required by `std::thread::spawn`

【问题讨论】:

    标签: rust thread-safety lifetime


    【解决方案1】:

    我发现错误消息非常简单:

    • 特征std::marker::Send 没有为Expr + 'static 实现
    • 是必需的,因为对 std::marker::Send 的实现要求 std::sync::Arc&lt;Expr + 'static&gt;
    • 必需,因为它出现在 Container 类型中
    • 是必需的,因为对 std::marker::Send 的 impl 的要求为 std::sync::Arc&lt;Container&gt;
    • 必需,因为它出现在 [closure@src/main.rs:64:33: 67:6 container1:std::sync::Arc&lt;Container&gt;] 类型中
    • std::thread::spawn 要求

    您正试图将您的 Arc&lt;Container&gt; 移动到另一个线程,但它包含一个 Arc&lt;Expr + 'static&gt;,不能保证它可以安全地发送 (Send) 或跨线程共享 (Sync)。

    SendSync 作为超特征添加到Expr:

    pub trait Expr: Send + Sync { /* ... */ }
    

    或者将它们作为 trait bound 添​​加到你的 trait 对象中:

    pub struct AddExpr {
        expr1: Box<Expr + Send + Sync>,
        expr2: Box<Expr + Send + Sync>,
    }
    
    impl AddExpr {
        pub fn new(expr1: Box<Expr + Send + Sync>, expr2: Box<Expr + Send + Sync>) -> Self {
            Self { expr1, expr2 }
        }
    }
    
    struct Container {
        x: i32,
        cached_expr: Arc<Expr + Send + Sync>,
    }
    

    另见:

    【讨论】:

      猜你喜欢
      • 2016-03-20
      • 1970-01-01
      • 2021-07-22
      • 2019-01-08
      • 1970-01-01
      • 1970-01-01
      • 2021-05-24
      • 1970-01-01
      • 2010-11-29
      相关资源
      最近更新 更多