简体   繁体   English

将对象传递给生锈的线程

[英]Passing an object to a thread in rust

I'm used to writing code in python and C++ and try to get along with rust.我习惯用 python 和 C++ 编写代码,并尝试与 Rust 相处。 I want to pass an object to a thread and call a method of this object.我想将一个对象传递给线程并调用该对象的方法。 In addition, the object is passed to the thread by dependency injection because I aim to reuse this module.另外,通过依赖注入将对象传递给线程,因为我的目标是重用这个模块。 When the function expects the Object FIFO , everything's fine.当函数需要 Object FIFO时,一切都很好。 But when using the trait, it fails.但是当使用特性时,它失败了。

I get the following error when passing the clone of the object to the thread:将对象的克隆传递给线程时出现以下错误:

borrowed data escapes outside of function requirement occurs because of the type Mutex<&dyn testTrait> , which makes the generic argument &dyn testTrait invariant the struct Mutex<T> is invariant over the parameter T由于类型Mutex<&dyn testTrait>发生借用数据逃逸到函数要求之外,这使得通用参数&dyn testTrait不变 struct Mutex<T>在参数T上不变

use std::thread;
use std::sync::{Arc, Mutex};

pub trait testTrait: Send + Sync {
    fn test(&self, i: i32) -> i32;
}

pub struct FIFO {}

unsafe impl Send for FIFO {}
unsafe impl Sync for FIFO {}

impl testTrait for FIFO {
    fn test(&self, i: i32) -> i32 {
        return i;
    }
}

impl FIFO {}

fn main() {
    let fifo = FIFO {};
    caller(&fifo);
}

pub fn caller(t: &dyn testTrait) {
    let a = Arc::new(Mutex::new(t));
    let clone = a.clone();
    thread::spawn(move || {
        if let Ok(mut x) = clone.lock() {
            x.test(5);
        }
    });
}

Using a reference in this situation is probably the wrong choice, because a reference connects the lifetime of the thread with the calling function.在这种情况下使用引用可能是错误的选择,因为引用将线程的生命周期与调用函数联系起来。

This problem is not specific to Rust, Rust just complains about it because Rust has a zero-undefined-behavior tolerance.这个问题不是 Rust 特有的,Rust 只是抱怨它,因为 Rust 具有零未定义行为容忍度。

In C++, for example, it is undefined behavior:例如,在 C++ 中,它是未定义的行为:

#include <iostream>
#include <thread>
#include <chrono>

struct TestTrait {
  virtual int test() = 0;
};

struct Foo : TestTrait {
  int value;
  int test() override { return value; }
};

int main() {
  {
    Foo x;
    x.value = 10;

    std::thread thrd([&x]() {
      std::cout << x.test() << std::endl;
    });
    thrd.detach();
  }

  std::this_thread::sleep_for(std::chrono::milliseconds(100));

  return 0;
}
Segmentation fault

So as @PitaJ already points out, there are two solutions:正如@PitaJ 已经指出的那样,有两种解决方案:

  • Make sure the thread doesn't outlive the main function by usingstd::thread::scope使用std::thread::scope确保线程的寿命不会超过main函数
  • Make the data reference counted via Arc通过Arc使数据引用计数

I assume you want to go the Arc route because you already started with that.我假设你想走Arc路线,因为你已经开始了。 You can't place the reference in the Arc , though, you have to put the object itself into the Arc .您不能将引用放在Arc中,但是,您必须将对象本身放入Arc中。 The whole point of an Arc is to have multiple ownership, and for that, the Arc has to actually own the object, not borrow it. Arc的全部意义在于拥有多个所有权,为此, Arc必须实际拥有该对象,而不是借用它。

Here is a possible solution with Arc :这是Arc的可能解决方案:

use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;

pub trait TestTrait: Send + Sync {
    fn test(&mut self, i: i32) -> i32;
}

pub struct FIFO {}

impl TestTrait for FIFO {
    fn test(&mut self, i: i32) -> i32 {
        return i;
    }
}

impl FIFO {}

fn main() {
    let fifo = Arc::new(Mutex::new(FIFO {}));
    caller(Arc::clone(&fifo));
    std::thread::sleep(Duration::from_millis(100));
}

pub fn caller(t: Arc<Mutex<impl TestTrait + 'static>>) {
    thread::spawn(move || {
        if let Ok(mut x) = t.lock() {
            println!("{}", x.test(5));
        }
    });
}
5

Note that:注意:

  • You need to use impl instead of dyn as this situation is too complex for trait objects您需要使用impl而不是dyn ,因为这种情况对于 trait 对象来说太复杂了
  • No need to use unsafe anywhere;无需在任何地方使用unsafe in fact, you should never define Send and Sync manually, as they are derived automatically事实上,你永远不应该手动定义SendSync ,因为它们是自动派生的

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM