I have a struct which holds an Arc
and I\'m trying to add a method which takes ownership of self
, and moves the ownershi
How does this work?
Let's check the requirements of thread::spawn again:
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:
impl<T> Send for Arc<T>
where
T: Send + Sync + ?Sized,
So Arc<T>
implements Send
if T
implements Send
and Sync
. And while Receiver implements Send, it does not implement Sync.
So why does Arc
have such strong requirements for T
? T
also has to implement Send
because Arc
can act like a container; 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. The interesting part is to see why T
also has to implement Sync
, which is apparently also the part you are struggling with:
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. Consider if you would add a #[derive(Clone)]
to Foo
later (which is possible without a problem):
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. And this is no good, since Receiver
does not implement Sync
!
To me this code raises the question: why the Arc
in the first place? As you noticed, without the Arc
, it works without a problem: you clearly state that Foo
is the only owner of the Receiver
. And if you are "not trying to share [the Receiver]" anyway, there is no point in having multiple owners.