I'm trying to write a function that starts a job in background and returns a callback that will terminate this task. This is the implementation:
// Spawn a task in a new thread
// The task will be given a Receiver<()>
// The task must perform cleanup and shutdown when data is sent on that receiver
// Calling the closure returned by this function will send shutdown notification to the task and
// block until the task is finished
pub fn spawn_task(task: fn(flume::Receiver<()>)) -> Box<dyn Fn()> {
let (ctrl_tx, ctrl_rx) = flume::bounded::<()>(1);
let thread = std::thread::spawn(move || task(ctrl_rx));
Box::new(move || {
let _ = ctrl_tx.send(());
let _ = thread.join();
})
}
The compilation fails with an error saying "cannot move out of thread
, a captured variable in an Fn
closure".
It compiles if I rewrite the function to explicitly return an object with the context needed for the callback to work:
pub struct AsyncTaskContext {
thread: JoinHandle<()>,
ctrl_tx: Sender<()>,
}
impl AsyncTaskContext {
pub fn join(self) {
let _ = self.ctrl_tx.send(());
let _ = self.thread.join();
}
}
pub fn spawn_task_with_type(task: fn(flume::Receiver<()>)) -> AsyncTaskContext {
let (ctrl_tx, ctrl_rx) = flume::bounded::<()>(1);
let thread = std::thread::spawn(move || task(ctrl_rx));
AsyncTaskContext { thread, ctrl_tx }
}
Why doesn't the first implementation work as expected?