跨线程共享具有特征对象作为属性的结构

Adr*_*des 1 thread-safety lifetime rust

我有下面的代码。随着注释掉的部分,它的工作。当我取消注释这些部分时,它不再编译。

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

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

我读过 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();
}
Run Code Online (Sandbox Code Playgroud)

错误:

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();
}
Run Code Online (Sandbox Code Playgroud)

She*_*ter 6

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

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

您正在尝试将您的Arc<Container>线程移动到另一个线程,但它包含一个Arc<Expr + 'static>,不能保证跨线程安全地发送 ( Send) 或共享 ( Sync)。

SendSync作为超特征添加到 Expr:

pub trait Expr: Send + Sync { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

或者将它们作为 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>,
}
Run Code Online (Sandbox Code Playgroud)

也可以看看: