[英]Why do I get an error that "Sync is not satisfied" when moving self, which contains an Arc, into a new thread?
I have a struct which holds an Arc<Receiver<f32>>
and I'm trying to add a method which takes ownership of self
, and moves the ownership into a new thread and starts it.我有一个包含Arc<Receiver<f32>>
,我正在尝试添加一个方法,该方法获取self
的所有权,并将所有权移动到一个新线程中并启动它。 However, I'm getting the error但是,我收到错误
error[E0277]: the trait bound `std::sync::mpsc::Receiver<f32>: std::marker::Sync` is not satisfied
--> src/main.rs:19:9
|
19 | thread::spawn(move || {
| ^^^^^^^^^^^^^ `std::sync::mpsc::Receiver<f32>` cannot be shared between threads safely
|
= help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Receiver<f32>`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<std::sync::mpsc::Receiver<f32>>`
= note: required because it appears within the type `Foo`
= note: required because it appears within the type `[closure@src/main.rs:19:23: 22:10 self:Foo]`
= note: required by `std::thread::spawn`
If I change the struct to hold an Arc<i32>
instead, or just a Receiver<f32>
, it compiles, but not with a Arc<Receiver<f32>>
.如果我将结构更改为保存Arc<i32>
或仅保存Receiver<f32>
,则它会编译,但不会使用Arc<Receiver<f32>>
编译。 How does this work?这是如何运作的? The error doesn't make sense to me as I'm not trying to share it between threads (I'm moving it, not cloning it).该错误对我来说没有意义,因为我不想在线程之间共享它(我正在移动它,而不是克隆它)。
Here is the full code:这是完整的代码:
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::Arc;
use std::thread;
pub struct Foo {
receiver: Arc<Receiver<f32>>,
}
impl Foo {
pub fn new() -> (Foo, Sender<f32>) {
let (sender, receiver) = channel::<f32>();
let sink = Foo {
receiver: Arc::new(receiver),
};
(sink, sender)
}
pub fn run_thread(self) -> thread::JoinHandle<()> {
thread::spawn(move || {
println!("Thread spawned by 'run_thread'");
self.run(); // <- This line gives the error
})
}
fn run(mut self) {
println!("Executing 'run'")
}
}
fn main() {
let (example, sender) = Foo::new();
let handle = example.run_thread();
handle.join();
}
How does this work?这是如何运作的?
Let's check the requirements ofthread::spawn
again:让我们再次检查thread::spawn
的要求:
pub fn spawn<F, T>(f: F) -> JoinHandle<T>
where
F: FnOnce() -> T,
F: Send + 'static, // <-- this line is important for us
T: Send + 'static,
Since Foo
contains an Arc<Receiver<_>>
, let's check if and how Arc
implements Send
:由于Foo
包含Arc<Receiver<_>>
,让我们检查Arc
是否以及如何实现Send
:
impl<T> Send for Arc<T>
where
T: Send + Sync + ?Sized,
So Arc<T>
implements Send
if T
implements Send
and Sync
.所以Arc<T>
实现了Send
如果T
实现了Send
和Sync
。 And while Receiver
implements Send
, it does not implement Sync
.虽然Receiver
实现了Send
, 但它没有实现Sync
。
So why does Arc
have such strong requirements for T
?那么为什么Arc
对T
有如此强烈的要求呢? T
also has to implement Send
because Arc
can act like a container; T
还必须实现Send
因为Arc
可以充当容器; if you could just hide something that doesn't implement Send
in an Arc
, send it to another thread and unpack it there... bad things would happen.如果你可以隐藏一些没有在Arc
实现Send
东西,把它发送到另一个线程并在那里解压......坏事会发生。 The interesting part is to see why T
also has to implement Sync
, which is apparently also the part you are struggling with:有趣的部分是看看为什么T
还必须实现Sync
,这显然也是您正在努力解决的部分:
The error doesn't make sense to me as I'm not trying to share it between threads (I'm moving it, not cloning it).该错误对我来说没有意义,因为我不想在线程之间共享它(我正在移动它,而不是克隆它)。
The compiler can't know that the Arc
in Foo
is in fact not shared.编译器无法知道Foo
中的Arc
实际上没有共享。 Consider if you would add a #[derive(Clone)]
to Foo
later (which is possible without a problem):考虑您是否会稍后向Foo
添加#[derive(Clone)]
(这可能没有问题):
fn main() {
let (example, sender) = Foo::new();
let clone = example.clone();
let handle = example.run_thread();
clone.run();
// oopsie, now the same `Receiver` is used from two threads!
handle.join();
}
In the example above there is only one Receiver
which is shared between threads.在上面的例子中,只有一个Receiver
在线程之间共享。 And this is no good, since Receiver
does not implement Sync
!这不好,因为Receiver
没有实现Sync
!
To me this code raises the question: why the Arc
in the first place?对我来说,这段代码提出了一个问题:首先为什么是Arc
? As you noticed, without the Arc
, it works without a problem: you clearly state that Foo
is the only owner of the Receiver
.正如您所注意到的,没有Arc
,它的工作没有问题:您明确声明Foo
是Receiver
的唯一所有者。 And if you are "not trying to share [the Receiver]" anyway, there is no point in having multiple owners.而且,如果您“无论如何都不想共享 [接收者]”,那么拥有多个所有者是没有意义的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.