1

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.

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();
}

The error:

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`

1 Answer 1

6

I find the error message pretty straightforward:

  • 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

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.

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

See also:

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.