[自用][操作系统]线程

📅 发布时间:2026/7/4 5:11:53 👁️ 浏览次数:
[自用][操作系统]线程
创建线程和在线程间传递数据std::thread::spawn创建一个新线程move闭包捕获变量的所有权JoinHandle::join()等待线程完成并获取返回值## 高级线程操作 //! - **线程睡眠**thread::sleep 暂停当前线程。 //! - **线程本地存储**thread_local! 宏定义每个线程独有的静态变量。 //! - **线程命名**Builder::name 为调试目的分配名称。 //! - **线程优先级**通过 thread::Builder 设置依赖平台。 //! - **线程池**像 rayon 这样的库管理线程复用。 //! - **线程通信**使用 std::sync::mpsc多生产者单消费者或第三方 crate例如 crossbeam。 //! - **共享状态**ArcMutexT 或 ArcRwLockT 安全地在线程间共享可变数据。 //! - **同步原语**Barrier 同步多个线程Condvar 实现条件变量。 //! - **线程暂停与唤醒**thread::park 阻塞线程unpark 唤醒它适用于自定义调度。 //! - **获取当前线程句柄**thread::current()。 //! - **作用域线程**crossbeam::scope 或标准库的 thread::scopeRust 1.63允许线程借用栈上的数据而无需 move。 //! //! Rust 通过所有权系统以及 Send 和 Sync trait 在编译时防止数据竞争。 //! 实现了 Send 的类型可以跨线程边界传递。 //! 实现了 Sync 的类型可以同时被多个线程引用。 //! 大多数 Rust 标准类型都是 Send Sync例外情况包括 RcT非原子引用计数和裸指针。thread::Builder给线程分配名字和设置栈的大小。letbuilderthread::Builder::new().name(my-worker.into()).stack_size(32*1024);// 32 KiBusestd::thread;//假设线程不会创建失败fnnamed_thread_example(){letbuilderthread::Builder::new().name(my-worker.into())//名字.stack_size(32*1024);// 32 KiB分配栈大小lethandlebuilder.spawn(||{println!(Hello from thread: {:?},thread::current().name());42}).unwrap();//spawn返回ResultJoinHandleT, io::Errorunwrap()把JoinHandle传递给父进程letresulthandle.join().unwrap();//handle.join()等待子进程结束返回ResultT, Boxdyn Any Send如果创建成功join()返回OK(42)如果不成功返回Err//unwrap()会导致当前线程panicprintln!(Thread returned: {},result);}作用域线程scoped threads借用函数栈的变量但不会把数据所有权move进去。usestd::thread;fnscoped_thread_example(){letavec![1,2,3];letbvec![4,5,6];let(sum_a,sum_b)thread::scope(|s|{leth1s.spawn(||a.iter().sum::i32());//创建一个进程必须在scope的作用域内销毁可以引用局部变量。leth2s.spawn(||b.iter().sum::i32());(h1.join().unwrap(),h2.join().unwrap())//直接提取join()的值如果没有则报错});// a and b are still accessible here.println!(sum_a {}, sum_b {},sum_a,sum_b);}作用域线程是可以引用局部变量的但是spawn线程引用的变量必须具有static属性也就是全局静态数据。因为在spawn创建的是独立线程在局部变量销毁的时候线程可能还没有结束。fnf(){letx10;thread::spawn(||{println!({},x);// 借用 x});}// x 在这里销毁但线程可能还没结束如果x销毁之后线程还没结束那么有关x的引用就会变成悬垂指针Rust编译器不会通过编译。线程局部存储同一个“变量名”在不同线程里其实各有一份独立的数据互不影响。usestd::cell::RefCell;//RefCell的作用是即使外面拿到的是不可变引用也能在运行时进行可变借用usestd::thread;thread_local!{//定义线性局部变量的宏staticTHREAD_ID:RefCellusizeRefCell::new(0);//每一个线程都有自己独立的THREAD_ID,初始值为0static表示每个线程各自拥有的一份静态局部存储。}fnthread_local_example(){THREAD_ID.with(|id|{//调用函数访问线程的ID并且把它传给闭包使用id是THREAD_ID的引用*id.borrow_mut()1;//borrow_mut() 会从 RefCell 里借出一个可变引用*解引用把usize改成1});//主线程先把自己的THREAD_ID设为1lethandlethread::spawn(||{//创建子进程THREAD_ID.with(|id|{*id.borrow_mut()2;});THREAD_ID.with(|id|println!(Thread local value: {},*id.borrow()));//不可变引用的解引用});handle.join().unwrap();//正常结束拿出来值panic则errTHREAD_ID.with(|id|println!(Main thread value: {},*id.borrow()));}