Rust技术问询:如何将引用移入新线程?
Rust线程中传递栈变量引用的解决方案
你的代码存在两个核心问题:
- 要修改
sts的值,需要传递可变引用&mut u8而非不可变引用&u8; - 普通
thread::spawn无法安全捕获栈变量的引用——Rust编译器无法保证子线程结束前,父线程的栈变量依然存活,因此会直接拒绝这种写法。
用作用域线程(Scoped Threads)解决问题
作用域线程通过std::thread::scope创建,它能保证所有在作用域内启动的子线程,都会在作用域闭包执行完毕前结束,以此确保栈变量的生命周期覆盖子线程的整个运行周期,让编译器认可这种引用的安全性。
调整后的代码实现(适配你的模块结构)
use std::thread; use std::thread::ScopedJoinHandle; pub mod tds { use super::*; pub fn f<'scope>(sts: &'scope mut u8) -> ScopedJoinHandle<'scope, ()> { // 创建作用域,在其中启动子线程 thread::scope(|s| { s.spawn(move || { *sts = 88; println!("flow: {:?}", sts); }) }) .into_iter() .next() .unwrap() } } fn main() { let mut sts: u8 = 5; // 传递可变引用给函数 let handle = tds::f(&mut sts); println!("main_01: {:?}", sts); // 等待子线程完成 handle.join().unwrap(); println!("main_02: {:?}", sts); }
更简洁的写法(直接在main中使用作用域)
如果不需要封装成模块函数,这种写法更直观:
use std::thread; fn main() { let mut sts: u8 = 5; // 定义线程作用域 thread::scope(|s| { // 在作用域内启动子线程,直接捕获sts的可变引用 let handle = s.spawn(|| { *sts = 88; println!("flow: {:?}", &sts); }); println!("main_01: {:?}", sts); // 等待子线程执行完毕 handle.join().unwrap(); }); // 作用域结束后,sts依然可用 println!("main_02: {:?}", sts); }
关键说明
thread::scope会强制等待所有内部子线程完成后才退出闭包,彻底消除了悬垂引用的风险;- 必须使用可变引用
&mut u8才能修改sts的值,这是Rust可变规则的要求; - 作用域线程的
ScopedJoinHandle带有生命周期标记,确保它不会超出作用域变量的生命周期范围。
内容的提问来源于stack exchange,提问作者inshade
相关产品推荐
相关产品推荐

