与特质对象共享结构作为跨线程的属性 [英] Sharing a struct with trait objects as properties across threads

查看:71
本文介绍了与特质对象共享结构作为跨线程的属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有下面的代码.使用注释掉的部分,它可以正常工作.当我取消注释部分时,它将不再编译.

I have the code below. With the commented out parts, it's working. When I uncomment the parts it does not compile anymore.

如何调整注释的部分以使其起作用,即,我想使线程同时访问表达式树.

How can I adjust the commented parts to make them work, i.e., I want to make threads access the expression tree simultaneously.

尝试时,编译器会从有关线程安全性的错误开始.

When I try it, the compiler starts with errors about thread safeness.

我阅读了Rust的书,并且了解C/C ++,但还不了解Rust类型系统和语义的所有知识.

I read the Rust book and know C/C++, but didn't understood everything about Rust type system and semantics yet.

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`

推荐答案

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

I find the error message pretty straightforward:

  • 特征std::marker::Send不适用于Expr + 'static
  • 之所以需要
  • ,是因为std::marker::Sendstd::sync::Arc<Expr + 'static>的隐含要求
  • 必需的,因为它出现在类型Container
  • 之所以需要
  • ,是因为std::sync::Arc<Container>
  • std::marker::Send的隐含要求
  • 必需的,因为它出现在类型[closure@src/main.rs:64:33: 67:6 container1:std::sync::Arc<Container>]
  • std::thread::spawn 所需
  • the trait std::marker::Send is not implemented for Expr + 'static
  • required because of the requirements on the impl of std::marker::Send for std::sync::Arc<Expr + 'static>
  • required because it appears within the type Container
  • required because of the requirements on the impl of std::marker::Send for std::sync::Arc<Container>
  • required because it appears within the type [closure@src/main.rs:64:33: 67:6 container1:std::sync::Arc<Container>]
  • required by std::thread::spawn

您正在尝试将Arc<Container>移到另一个线程,但是它包含一个Arc<Expr + 'static>,不能保证可以安全地在各个线程之间发送(c12)或共享(c13).

You are trying to move your Arc<Container> to another thread, but it contains an Arc<Expr + 'static>, which cannot be guaranteed to be safely sent (Send) or shared (Sync) across threads.

SendSync作为超级特征添加到Expr:

Either add Send and Sync as supertraits to Expr:

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

或将它们作为特征绑定添加到特征对象:

Or add them as trait bounds to your trait objects:

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>,
}

另请参阅:

  • How can I share references across threads?
  • Multithreaded application fails to compile with error-chain
  • Is there any way to implement the Send trait for ZipFile?
  • How do I share a generic struct between threads using Arc<Mutex<MyStruct<T>>>?

这篇关于与特质对象共享结构作为跨线程的属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆