[英]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 structMutex<T>
is invariant over the parameterT
由于类型
Mutex<&dyn testTrait>
发生借用数据逃逸到函数要求之外,这使得通用参数&dyn testTrait
不变 structMutex<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 已经指出的那样,有两种解决方案:
main
function by usingstd::thread::scope
std::thread::scope
确保线程的寿命不会超过main
函数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:注意:
impl
instead of dyn
as this situation is too complex for trait objectsimpl
而不是dyn
,因为这种情况对于 trait 对象来说太复杂了unsafe
anywhere;unsafe
; in fact, you should never define Send
and Sync
manually, as they are derived automaticallySend
和Sync
,因为它们是自动派生的
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.