Ch 29: std::thread - 线程基础
std::thread模块提供了Rust中的多线程编程支持。Rust的线程模型是1:1的,即每个语言级线程对应一个操作系统线程。
2. 基本线程创建
Section titled “2. 基本线程创建”使用thread::spawn创建新线程:
use std::thread;
fn main() { let handle = thread::spawn(|| { println!("子线程执行中..."); 42 });
println!("主线程继续执行");
// 等待子线程完成并获取结果 let result = handle.join().unwrap(); println!("子线程返回: {}", result);}3. move闭包
Section titled “3. move闭包”闭包中的move关键字用于转移所有权:
use std::thread;
fn main() { let data = vec![1, 2, 3];
// move转移data的所有权到子线程 let handle = thread::spawn(move || { println!("子线程中的数据: {:?}", data); // data在这里被使用后drop });
// 主线程无法再使用data // println!("{:?}", data); // 编译错误!
handle.join().unwrap();}4. thread::sleep - 线程睡眠
Section titled “4. thread::sleep - 线程睡眠”use std::thread;use std::time::Duration;
fn main() { println!("开始...");
thread::sleep(Duration::from_secs(1)); println!("1秒后...");
thread::sleep(Duration::from_millis(500)); println!("再过0.5秒...");
// 支持纳秒精度 thread::sleep(Duration::from_nanos(1_000_000)); println!("1毫秒后...");}方法签名:
pub fn sleep(dur: Duration)5. Thread::Builder - 自定义线程
Section titled “5. Thread::Builder - 自定义线程”Builder允许设置线程名称和栈大小:
use std::thread;
fn main() { let builder = thread::Builder::new() .name("worker-1".to_string()) .stack_size(4 * 1024 * 1024); // 4MB栈
let handle = builder.spawn(|| { println!("线程名: {:?}", thread::current().name()); println!("线程ID: {:?}", thread::current().id()); }).unwrap();
handle.join().unwrap();}Builder方法签名:
impl Builder { pub fn new() -> Builder pub fn name(self, name: String) -> Builder pub fn stack_size(self, size: usize) -> Builder pub fn spawn<F, T>(self, f: F) -> Result<JoinHandle<T>> where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static}6. JoinHandle - 线程句柄
Section titled “6. JoinHandle - 线程句柄”spawn返回JoinHandle,用于等待线程结束:
use std::thread;
fn main() { let handle = thread::spawn(|| { "Hello from thread" });
// join返回Result match handle.join() { Ok(result) => println!("线程返回: {}", result), Err(e) => println!("线程panic: {:?}", e), }}7. thread::current - 获取当前线程信息
Section titled “7. thread::current - 获取当前线程信息”use std::thread;
fn main() { let handle = thread::spawn(|| { let current = thread::current();
println!("线程ID: {:?}", current.id()); println!("线程名: {:?}", current.name());
// 检查是否是主线程 println!("是主线程: {}", current.is_main()); });
println!("主线程ID: {:?}", thread::current().id()); println!("是主线程: {}", thread::current().is_main());
handle.join().unwrap();}8. thread::scope - 作用域线程
Section titled “8. thread::scope - 作用域线程”scope确保所有线程在函数返回前完成:
use std::thread;
fn main() { let data = vec![1, 2, 3, 4, 5];
// 所有子线程必须在scope返回前完成 thread::scope(|scope| { for i in &data { scope.spawn(|| { println!("处理: {}", i); }); } });
println!("所有线程已完成,data仍可访问: {:?}", data);}9. LocalKey - 线程局部存储
Section titled “9. LocalKey - 线程局部存储”使用thread_local!创建线程局部变量:
use std::cell::RefCell;use std::thread;
thread_local! { static THREAD_DATA: RefCell<String> = RefCell::new("初始值".to_string());}
fn main() { THREAD_DATA.with(|data| { println!("主线程: {}", data.borrow()); });
let handle = thread::spawn(|| { THREAD_DATA.with(|data| { data.borrow_mut().push_str(" - 被线程修改"); println!("子线程: {}", data.borrow()); }); });
handle.join().unwrap();
// 主线程的值不受影响 THREAD_DATA.with(|data| { println!("主线程(不变): {}", data.borrow()); });}10. 线程parking
Section titled “10. 线程parking”use std::thread;use std::time::Duration;
fn main() { let handle = thread::spawn(|| { println!("线程开始park"); thread::park(); println!("线程恢复执行"); });
println!("主线程sleep 1秒"); thread::sleep(Duration::from_secs(1));
println!(" unpark 子线程"); handle.thread().unpark(); handle.join().unwrap();}11. 注意事项
Section titled “11. 注意事项”- panic处理:panic在单个线程中不会导致整个程序崩溃
- 资源清理:JoinHandle被drop时如果线程未结束,会自动detach成为守护线程
- 栈大小:默认栈大小约2MB,可通过Builder调整
- 线程数量:受限于系统线程数和资源
- LocalKey:使用
with方法访问,必须提供初始值
12. 总结
Section titled “12. 总结”std::thread核心API:
thread::spawn()- 创建线程move闭包 - 转移所有权thread::sleep()- 线程睡眠Builder- 自定义线程属性JoinHandle- 管理线程生命周期thread::current()- 获取当前线程信息scope()- 安全的作用域线程LocalKey- 线程局部存储
Rust的线程安全通过所有权和类型系统保证,是构建并发程序的基础。