与特质对象共享结构作为跨线程的属性 [英] Sharing a struct with trait objects as properties across threads
问题描述
我有下面的代码.使用注释掉的部分,它可以正常工作.当我取消注释部分时,它将不再编译.
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::Send
对std::sync::Arc<Expr + 'static>
的隐含要求 - 必需的,因为它出现在类型
Container
中
- 之所以需要
- ,是因为
std::sync::Arc<Container>
对 - 必需的,因为它出现在类型
[closure@src/main.rs:64:33: 67:6 container1:std::sync::Arc<Container>]
中
std::marker::Send
的隐含要求
std::thread::spawn
所需
- the trait
std::marker::Send
is not implemented forExpr + 'static
- required because of the requirements on the impl of
std::marker::Send
forstd::sync::Arc<Expr + 'static>
- required because it appears within the type
Container
- required because of the requirements on the impl of
std::marker::Send
forstd::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.
将Send
和Sync
作为超级特征添加到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屋!