I'd like to know if it's possible to return a thread-local value from a thread:
pub fn compile(req: FineTunedCompileRequest) -> JoinHandle<CompilerResult> {
// Spawn a thread for the compilation
std::thread::spawn(|| {
tokio::runtime::Runtime::new().unwrap().block_on(async move {
let FineTunedCompileRequest {
dir,
workspace_dir,
client,
lockfile,
lockfile_path,
} = req;
todo!()
})
})
}
CompilerResult here consists of a pair of Rcs which further contain other Rc and are totally thread-local. I'm getting an error complaning about that, but not as I expected (I thought join_handle.join().unwrap() could return anything).
There's no way to say "this type is Send under certain conditions" in safe code, and so Rc is always not Send. And join moves a value from one thread to another, which is exactly what Send allows. The Send bound isn't on join, but you can only create JoinHandle by spawn, which puts the bound on its closure.
Depending on what it does, you may be able to unsafe impl Send for CompilerResult {}, but a simpler solution is to just use Arc instead of Rc.
I see, thanks. I decided to do compilation at the same thread I run some compiler processes, while the language server stays at the main thread.
Also it's difficulty to replace Rc by Arc in my project as it's very large and it also uses other thread-local types like RefCell (parser + semantic model + verifier...).
In case it matters (it likely doesn’t), note that Arc doesn’t require its contents to be Send + Sync — you can always substitute Arc<T> for Rc<T>, and if T isn't Send + Sync, then the only consequence is that Arc<T> isn’t Send + Sync. So, if the problem is only that you have generic code that uses Rc, you can swap in Arc. But this doesn’t help if the value you want to return from the thread contains a RefCell.