当前位置: 首页 > news >正文

Rust_2025:阶段1:day6.2 Box ,Cow ,Rc ,Refcell ,Arc,线程(join(),lock(),子线程与主线程通信

并发编程

  1. 程序可以有多个线程栈,但只能有一个堆
  2. 子线程崩溃不会导致影响主线程,但主线程崩溃会导致程序停止,自然子线程也就死了

堆类型和堆指针

Box

  1. Box可以创建一个新的堆,可以在堆上自由修改数据
  • 基本用法
let p = Box::new(Point { x: 1, y: 2 });	//自动推断类型并赋给p
let b = Box::new(5);	//自动识别为i32,付给b一个32位整形值
let b = Box::new<u32>(5);	//强制赋值u32

注:与cpp不同,new的形参是初始化,并非内存大小

  1. 特点
  • Box类型的指针拥有Box类型的所有权
  • 只有自己能修改这块堆的值,无法给予其他人可变引用

Box实现链表

#[derive(PartialEq, Debug)]
pub enum List {Cons(i32, Box<List>),Nil,
}fn main() {println!("This is an empty cons list: {:?}", create_empty_list());println!("This is a non-empty cons list: {:?}",create_non_empty_list());
}pub fn create_empty_list() -> List {List::Nil
}pub fn create_non_empty_list() -> List {List::Cons(0 , Box::new(List::Nil))
}

Cow

  1. 这种指针可以指向任意的堆区域,获取其不可变引用。
  2. to_mut()方法可以复制指向的堆区域,原来的指针名获取其所有权。
fn abs_all<'a, 'b>(input: &'a mut Cow<'b, [i32]>) -> &'a mut Cow<'b, [i32]> {for i in 0..input.len() {let v = input[i];if v < 0 {// Clones into a vector if not already owned.input.to_mut()[i] = -v;}}input
}

Rc

  1. 特点:可以使一个堆区域获得多个不可变引用。

Refcell

  1. 特点: 可以使一个堆区域获得一个可变引用权,但只能使用方法隐式调用(运行时可以检测是否有多个可变引用)。
use std::cell::RefCell;
let data = RefCell::new(5);
*data.borrow_mut() = 10; // 修改数据
println!("{}", data.borrow()); // 读取数据

Refcell+Rc组合使用获取多个可变引用

use std::rc::Rc;
use std::cell::RefCell;struct Node {value: i32,next: Option<Rc<RefCell<Node>>>,
}fn main() {let a = Rc::new(RefCell::new(Node { value: 1, next: None }));let b = Rc::new(RefCell::new(Node { value: 2, next: Some(a.clone()) }));// 多个 Rc 指针可以共享同一个 Node// RefCell 允许在 Rc 管理下对 Node 进行可变借用b.borrow_mut().value = 3;
}

为什么必须要Rc套Refcell而并非Refcell套Rc?

  • 我的答案是:Refcell并非本身能使堆区域可变,而是可以用方法操控其堆区域。
  • 如果是Refcell套Rc的new,则Refcell只能通过方法修改Rc的索引的堆区域,而并非数据堆区域。

Arc

fn main() {let numbers: Vec<_> = (0..100u32).collect();let shared_numbers = Arc::new(numbers);// TODOlet mut joinhandles = Vec::new();for offset in 0..8 {let child_numbers = Arc::clone(&shared_numbers);// TODOjoinhandles.push(thread::spawn(move || {let sum: u32 = child_numbers.iter().filter(|&&n| n % 8 == offset).sum();println!("Sum of offset {} is {}", offset, sum);}));}for handle in joinhandles.into_iter() {handle.join().unwrap();}
}
  • Arc特指用在多个线程中的Rc
  • spawn会创建一个线程。spawn包含一个闭包参数(这里的move是可以自动识别闭包中需要的变量),创造一个子线程,此时主线程会继续运行。
  • joinhandles会存储线程信息。对joinhandles向量的一个元素调用join()会获取其线程信息,并检查是否异常。
  • 若线程正常结束,join()会返回Ok(返回值),否则会返回Err()。

Mutrex

  1. 类比Refcell之于Rc就是Mutrex之于Arc。

rust编译器自动解引用

  • 我认为,赋值的时候rust会自动解引用(因此Rust从不会返回引用地址)
  • 而在其他时候都不会自动解引用(传参)

Arc配合Mutrex

fn main() {let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));let mut handles = vec![];for _ in 0..10 {let status_shared = Arc::clone(&status);let handle = thread::spawn(move || {thread::sleep(Duration::from_millis(250));// TODO: You must take an action before you update a shared valuelet mut status = status_shared.lock().unwrap();status.jobs_completed += 1;});handles.push(handle);}for handle in handles {handle.join().unwrap();// TODO: Print the value of the JobStatus.jobs_completed. Did you notice// anything interesting in the output? Do you have to 'join' on all the// handles?}println!("jobs completed {}", status.lock().unwrap().jobs_completed);
}
  1. sleep只是普通的等待函数。
  2. Mutrex通过.lock()函数给线程中的变量一把锁(新的状态),当变量的生命周期结束后,锁才能给其他线程。拥有锁的变量才能读写Mutrex变量。
  3. lock()有三种状态:阻塞,成功,失败。

子线程与主线程通信

fn main() {let (tx, rx) = mpsc::channel();let queue = Queue::new();let queue_length = queue.length;send_tx(queue, tx);let mut total_received: u32 = 0;for received in rx {println!("Got: {}", received);total_received += 1;}println!("total numbers received: {}", total_received);assert_eq!(total_received, queue_length)
}
  1. mpsc是定义一组发送与接收端的函数
  2. tx是发送,rx是接收
  3. 当所有的发送端消失,对于rx的循环才会结束。
http://www.dtcms.com/a/392784.html

相关文章:

  • GD32VW553-IOT V2【微秒延迟时间实现方法】
  • html5是移动设备玖写口吧目盖由
  • 华为全联接大会 2025:跃升行业智能化
  • 采用Mayavi对BEV相机外参进行可视化
  • 算法高频题-动态规划
  • 第七篇:强类型枚举:enum class - 彻底解决传统枚举的缺陷
  • 汽车中的轻量化 AI 算法:驶向智能出行新未来
  • 《根治开放世界坐骑卡顿:从时钟同步到负载均衡的架构级解决方案》
  • 在线预览Office文件全攻略
  • Cordova打包Vue项目成APK——真机调试
  • DNS协议、ICMP协议、NAT技术
  • HTML5 基础与常用标签
  • 2023 CCPC Online vp补题-D
  • 阿勒泰羊区域公用品牌在京发布 多方合力打造“雪都牧歌·天选之羊”产业新生态
  • 【分布式技术】Redis 双集群主备部署方案” 的详细说明
  • (信号)频谱泄露和频谱混叠
  • 蓝桥杯2024年第15届B组试题D
  • 【软考中级 - 软件设计师 - 基础知识】数据结构之线性表
  • Tomcat工作机制与Servlet流程详解
  • Netty从0到1系列之Recycler对象池技术【1】
  • 开始 ComfyUI 的 AI 绘图之旅-SD3.5文生图和图生图(全网首发,官网都没有更新)(十五)
  • [数理逻辑] 决定性公理与勒贝格可测性 (III) 有限维情况
  • 浅谈 “混合检索”和“重排”
  • 计算机视觉与深度学习 | 基于Matlab的雾霾天气和夜间车牌识别系统关键技术与架构设计
  • 二、PyTorch张量学习教程:从小白到高手的实战之旅
  • 名字空间,异常与匿名函数
  • DCM项目wan 1.3b T2V模型comfyui改造流程尝试
  • python编写的第一个appium自动化测试脚本
  • 道客巴巴文库资料免费下载的方法(不需要第三方软件)
  • 【C++】STL详解(九)—priority_queue的使用与模拟实现