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

2024-03-14

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

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

当我尝试时,编译器会开始出现有关线程安全的错误。

我阅读了 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`

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

  • 特质std::marker::Send没有实施Expr + 'static
  • 由于 impl 的要求而需要std::marker::Send for std::sync::Arc<Expr + 'static>
  • 必需的,因为它出现在类型中Container
  • 由于 impl 的要求而需要std::marker::Send for 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)跨线程。

要么添加Send and Sync作为 Expr 的超特征:

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

或者将它们作为特征边界添加到特征对象中:

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

也可以看看:

  • 如何跨线程共享引用? https://stackoverflow.com/q/29540407/155423
  • 多线程应用程序无法编译并出现错误链 https://stackoverflow.com/q/46491293/155423
  • 有没有办法实现 ZipFile 的发送特征? https://stackoverflow.com/q/45690958/155423
  • 如何使用 Arc>> 在线程之间共享通用结构? https://stackoverflow.com/q/40035731/155423
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • 如何使用WSDL2Java生成的文件?

    我使用 axis2 1 5 中的 wsdl2java 生成了 java 文件 现在它在以下文件夹结构中生成文件 src net mycompany www services services 文件夹中的文件是 SessionIntegrat
  • HTML 输入 - 以编程方式设置输入值时撤消历史记录丢失

    我有一个 HTML 输入 当用户在其中输入内容时 我设置了 输入 事件来处理将输入更新为用户输入内容的过滤版本 以及更新选择开始和选择结束以实现流畅的用户体验 为了达到适当的效果 这种情况会不断发生 然而 我注意到 每当 JS 通过设置输入
  • 在这种情况下为什么会说“位图无法解析为类型”?

    我收到这个错误 在我的情况下我该如何解决这个问题 Bitmap cannot be resolved to a type 发生错误的行 public void onPageStarted WebView view String url Bi
  • 在 Eclipse 中输入 PHP 时数组初始值设定项缩进错误

    我在 首选项 gt PHP gt 代码样式 gt 格式化程序 gt 换行 上设置了首选数组初始值设定项缩进 但在键入数组初始值设定项缩进时 这是错误的 arr array ENTER CURSOR 当我期待时 arr array ENTER
  • 从 xhr.responseText 恢复 ArrayBuffer

    我需要从向我发送 Base64 答案的 http 请求中获取数组缓冲区 对于这个请求 我无法使用XMLHttpRequest responseType arraybuffer 我从该请求中得到的响应已通读xhr responseText 因
  • Windows 通知服务:尝试在 PHP 中创建 Toast 通知时出现 401 无效令牌

    我一直在尝试向模拟器发送 Toast 通知 我创建了 Windows Phone 8 1 应用程序并将其与商店中的应用程序关联 之后 我设法获取了必须用来调用通道 URI 的访问令牌 当我尝试使用通道 URI 和访问令牌发送 Toast 通
  • XSD 验证错误:找不到元素“soapenv:Envelope”的声明

    我尝试使用以下命令根据 XSD 验证我的 XMLhttp www freeformatter com xml validator xsd html http www freeformatter com xml validator xsd h
  • rgdal 不会安装在 AWS RStudio AMI 上

    我已成功启动最新的 RStudio AWS EC2 实例 louisaslett com RStudio 1 1383 R 3 4 2 ubuntu 16 04 LTS 64 在这种情况下 R 的运行基本符合预期 我可以安装和打开许多软件包
  • Delphi 视觉组件 - 远离 TFrame 基础? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 我应该如何在 Scala 和 Anorm 中使用 MayErr[IntegrityConstraintViolation,Int]?

    I use Anorm http scala playframework org documentation scala 0 9 1 anorm进行数据库查询 当我做一个executeUpdate 我应该如何进行正确的错误处理 它有返回类型
  • 伪代码归纳证明

    我不太明白如何在伪代码上使用归纳证明 它的工作方式似乎与在数学方程上使用它的方式不同 我正在尝试计算数组中可被 k 整除的整数的数量 Algorithm divisibleByK a k Input array a of n size nu
  • Python按顺序执行线程

    我有以下代码 导入线程 def send to server lst Some logic to send the list to the server while 1 lst for i in range 1000 lst append
  • Ruby 和 MySQL UTF-8 字符

    我正在切换一个Sinatra http www sinatrarb com从 SQLite3 到 MySQL 的应用程序 由于某种我无法理解的原因 当我使用 Ruby 从 MySQL 中提取数据时Sequel https rubygems
  • Angular-CLI 和 Bootstrap 4

    我使用 Angular 2 迈出了第一步 特别是我使用 Angular cli 官方工具来创建新项目 我以这种方式创建了一个新项目 ng new my project name 该项目已正确创建 之后我想安装 bootstrap 4 并按照
  • 反应流中的自定义节点;创建节点后将附加数据保存到节点

    这是我第一次介绍反应流 我希望创建一个自定义节点 创建后 用户可以在节点中输入信息并保存 显示它 从反应流自定义节点的文档 https reactflow dev docs guides custom nodes 他们有一个类似的例子 他们
  • Android Studio 中外部剥离共享库的本机调试

    我已经剥离和未剥离共享库 如何在使用 LLDB 在 Android Studio 中调试剥离时加载符号 我可以成功调试位于 jniLibs 文件夹中的完整未剥离的 so 但它太大了 部署时间太长 在调试配置中指定符号目录不适用于标准和实验性
  • 在android中实现Socket.io的最佳方式

    我计划通过以下方式在 android 中实现 Socket iothis https github com socketio socket io 基于聊天的应用程序的库 据我了解 图书馆似乎相当不错 我想知道如何维护single整个应用程序
  • 新的 PendingIntent 更新当前意图

    我试图在一段时间间隔后显示不同的通知 但发生的情况是它更新了当前的通知PendingIntent结果 即使我触发 4 5 个待处理的意图请求 我也只能收到一个通知 单击按钮后我会执行以下操作 try adapter OpenDB int i
  • 反复出现的成本难题

    我经常发现自己必须定义一个函数的两个版本 以便拥有一个 const 版本和一个非常量版本 通常是 getter 但并非总是如此 两者的区别仅在于 其中一个的输入和输出是常量 而另一个的输入和输出是非常量 该功能的核心 真正的工作 是相同的
  • 跨线程共享具有特征对象的结构作为属性

    我有下面的代码 有了注释掉的部分 它就可以工作了 当我取消注释这些部分时 它不再编译 如何调整注释部分以使它们工作 即我想让线程同时访问表达式树 当我尝试时 编译器会开始出现有关线程安全的错误 我阅读了 Rust 书籍并了解 C C 但还不