Reputation: 50190
I have this code. It starts a background thread and passes work to it. I want to be able wait for the background thread to close cleanly (I know there is no way for it to stop at the moment, and I know it should be in a Drop implementation too. I am just trying to get the basic bones going)
use std::sync::mpsc;
use std::sync::mpsc::{Receiver, Sender};
use std::thread;
use std::thread::JoinHandle;
pub struct S2 {
jh: JoinHandle<()>,
tx: Sender<i32>,
}
impl S2 {
pub fn new() -> S2 {
let (tx, rx): (Sender<i32>, Receiver<i32>) = mpsc::channel();
let jh = thread::spawn(move || loop {
let item = rx.recv().unwrap();
println!("got {:?}", item)
});
S2 { jh, tx }
}
pub fn queue(&self, item: i32) {
self.tx.send(item).expect("oops");
}
pub fn wait(&mut self) {
self.jh.join().expect("oops");
}
}
fn main() {
let s2 = S2::new();
s2.queue(42);
// s2.jh.join().expect("oops");
}
The commented out line works fine. But that exposes the implementation details to the caller. I want it in a method. But the method one wont compile.
Compiling tq3 v0.1.0 (C:\work\rust\tq3)
error[E0507]: cannot move out of `self.jh` which is behind a mutable reference
--> src\main.rs:32:9
|
32 | self.jh.join().expect("oops");
| ^^^^^^^ move occurs because `self.jh` has type `std::thread::JoinHandle<()>`, which does not implement the `Copy` trait
I have tried my usual guesses at satisfying rust but so far have not been able to find the right one.
Upvotes: 0
Views: 772
Reputation: 73490
The wait
function as you define it,
pub fn wait(&mut self) {
self.jh.join().expect("oops");
}
takes a mutable reference to an S2
. But JoinHandle::join
consumes the handle (it doesn't take a reference, but a value)
The key to understanding how to work around the error is to think about what state the S2 object will be in after s2.wait()
.
If you want the object to still be valid, but the join handle it contains will no longer be valid then the type of the handle can't be JoinHandle<()>
, but maybe Option<JoinHandle<()>>
.
If the object is no longer valid after a call to wait
, then you can make wait
take self
rather than &mut self
.
You can see examples with both these approaches here. They really deserve better error handling, especially the S3 case - where a double call to .wait()
should be handled better. (You can't do a double call on S2 in my version since the first call consumes your instance).
Upvotes: 1