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

Rust循环引用与多线程并发

循环引用与自引用

循环引用的概念

循环引用指的是两个或多个对象之间相互持有对方的引用。在 Rust 中,由于所有权和生命周期的严格约束,直接创建循环引用通常会导致编译失败。例如:

// 错误的循环引用示例
struct Node {next: Option<Box<Node>>,
}fn create_cycle() {let n1 = Box::new(Node { next: None });let n2 = Box::new(Node { next: Some(n1) }); // 编译错误n1.next = Some(n2); // 编译错误
}

在这个例子中,尝试创建一个简单的双向链表,但由于所有权转移问题,编译器会报错。

自引用结构体的实现

自引用结构体是指一个结构体内部包含对自身实例的引用。这种结构常用于实现树形数据结构或其他需要递归引用的场景。

use std::rc::{Rc, Weak};struct Node {value: i32,parent: Option<Weak<Rc<Node>>>,children: Vec<Rc<Node>>,
}impl Node {fn new(value: i32) -> Self {Node {value,parent: None,children: Vec::new(),}}fn add_child(&mut self, child: Rc<Node>) {self.children.push(child.clone());child.parent = Some(Rc::downgrade(&self));}
}

使用 Rc 和 Weak 解决循环引用

为了处理循环引用问题,Rust 提供了 Rc 和 Weak 两种类型:

  • Rc<T>: 引用计数类型,允许多个所有者。
  • Weak<T>: 对应于 Rc<T> 的弱引用版本,不会增加引用计数。

通过使用 Weak 可以打破循环引用,因为 Weak 不会增加其指向的对象的引用计数。

生命周期注解的应用

在 Rust 中,生命周期注解可以帮助编译器更好地理解引用之间的关系。特别是在自引用和循环引用的情况下,生命周期注解尤为重要。

// 定义一个带有生命周期注解的函数
fn process_node<'a>(node: &'a Node) {println!("Processing node with value: {}", node.value);// 访问子节点for child in &node.children {process_node(child); // 递归处理子节点}
}// 使用生命周期注解的结构体方法
impl<'a> Node {fn traverse<'b>(&'a self, visitor: &dyn Fn(&'b Node)) {visitor(self);for child in &self.children {child.traverse(visitor);}}
}

实际代码示例与分析

下面是一个完整的示例,展示了如何创建并操作自引用结构体:

use std::rc::{Rc, Weak};struct Node {value: i32,parent: Option<Weak<Rc<Node>>>,children: Vec<Rc<Node>>,
}impl Node {fn new(value: i32) -> Self {Node {value,parent: None,children: Vec::new(),}}fn add_child(&mut self, child: Rc<Node>) {self.children.push(child.clone());child.parent = Some(Rc::downgrade(&self));}
}fn main() {let root = Rc::new(Node::new(0));let child1 = Rc::new(Node::new(1));let child2 = Rc::new(Node::new(2));root.add_child(child1.clone());root.add_child(child2.clone());println!("Root has {} children", root.children.len());// 访问子节点的父节点if let Some(parent) = child1.parent {if let Some(p) = parent.upgrade() {println!("Child 1's parent is {}", p.value);}}// 遍历树结构root.traverse(&|node| println!("Visiting node with value: {}", node.value));
}

定义 Node 结构:

  • value: 节点存储的值。
  • parent: 父节点的弱引用,初始为 None。
  • children: 一个向量,存储子节点的强引用。

创建新节点:

  • new 方法初始化一个新的 Node 实例,此时没有父节点也没有子节点。

添加子节点:

  • add_child 方法接收一个 Rc<Node> 类型的参数作为子节点。
  • 将子节点添加到当前节点的 children 向量中。
  • 更新子节点的 parent 字段,使用 Rc::downgrade 转换为 Weak 引用。

遍历树结构:

  • traverse 方法使用生命周期注解,递归地遍历整个树结构。

多线程并发

并发与并行概述

  • 并发 (Concurrency): 多个任务可以在同一时间间隔内执行,但不一定在同一时刻执行。
  • 并行 (Parallelism): 多个任务在同一时刻执行,通常涉及硬件支持。

在 Rust 中,可以通过多线程实现并发,而并行则依赖于多核处理器的支持。

使用多线程

在 Rust 中,可以使用标准库中的 std::thread 模块来创建和管理线程。

创建线程

use std::thread;
use std::time::Duration;fn spawn_thread() {thread::spawn(|| {for i in 1..10 {println!("Thread spawned: {}", i);thread::sleep(Duration::from_millis(1));}});for i in 1..5 {println!("Main thread: {}", i);thread::sleep(Duration::from_millis(1));}
}fn main() {spawn_thread();
}

线程同步:消息传递

在 Rust 中,消息传递是一种常见的线程间通信方式。常用的工具包括 std::sync::mpsc 模块中的通道 (channel)。

使用通道

use std::sync::mpsc;
use std::thread;fn send_messages() {let (tx, rx) = mpsc::channel();thread::spawn(move || {let val = String::from("Hello from the other side!");tx.send(val).unwrap();});let received = rx.recv().unwrap();println!("Got: {}", received);
}fn main() {send_messages();
}

线程同步:锁

Rust 标准库提供了多种锁机制,如 Mutex、RwLock 和 Arc。

使用 Mutex

use std::sync::Mutex;
use std::thread;fn lock_data() {let counter = Mutex::new(0);let mut handles = vec![];for _ in 0..10 {let counter = Mutex::clone(&counter);let handle = thread::spawn(move || {let mut num = counter.lock().unwrap();*num += 1;});handles.push(handle);}for handle in handles {handle.join().unwrap();}println!("Counter: {}", *counter.lock().unwrap());
}fn main() {lock_data();
}

使用 RwLock

use std::sync::RwLock;
use std::thread;fn read_write_lock() {let data = RwLock::new(String::from("Hello"));let mut handles = vec![];for _ in 0..10 {let data = RwLock::clone(&data);let handle = thread::spawn(move || {let mut d = data.write().unwrap();*d += "!";});handles.push(handle);}for handle in handles {handle.join().unwrap();}println!("Data: {}", *data.read().unwrap());
}fn main() {read_write_lock();
}

线程同步:条件变量和信号量

Rust 标准库提供了 Condvar 和 Semaphore 等高级同步原语。

使用 Condvar

use std::sync::{Arc, Condvar, Mutex};
use std::thread;fn condition_variable() {let pair = Arc::new((Mutex::new(false), Condvar::new()));let pair_clone = Arc::clone(&pair);thread::spawn(move || {let (lock, cvar) = &*pair;let mut started = lock.lock().unwrap();*started = true;cvar.notify_one();});let (lock, cvar) = &*pair;let mut started = lock.lock().unwrap();while !*started {started = cvar.wait(started).unwrap();}println!("Condition variable signaled!");
}fn main() {condition_variable();
}

使用 Semaphore

use std::sync::Semaphore;
use std::thread;fn semaphore_example() {let sem = Semaphore::new(3);let mut handles = vec![];for _ in 0..5 {let sem = sem.clone();let handle = thread::spawn(move || {sem.acquire().unwrap();println!("Acquired semaphore");thread::sleep(std::time::Duration::from_secs(1));sem.release();});handles.push(handle);}for handle in handles {handle.join().unwrap();}
}fn main() {semaphore_example();
}

线程同步:原子操作与内存顺序

Rust 标准库提供了 std::sync::atomic 模块,用于原子操作和内存顺序控制。

原子操作

use std::sync::atomic::{AtomicUsize, Ordering};fn atomic_operations() {let counter = AtomicUsize::new(0);let mut handles = vec![];for _ in 0..10 {let counter = counter.clone();let handle = thread::spawn(move || {counter.fetch_add(1, Ordering::Relaxed);});handles.push(handle);}for handle in handles {handle.join().unwrap();}println!("Counter: {}", counter.load(Ordering::Relaxed));
}fn main() {atomic_operations();
}

内存顺序

use std::sync::atomic::{AtomicUsize, Ordering};fn memory_ordering() {let flag = AtomicUsize::new(0);let data = AtomicUsize::new(0);let mut handles = vec![];let flag_clone = flag.clone();let data_clone = data.clone();let handle1 = thread::spawn(move || {flag_clone.store(1, Ordering::Release);data_clone.store(42, Ordering::Relaxed);});let flag_clone = flag.clone();let data_clone = data.clone();let handle2 = thread::spawn(move || {while flag_clone.load(Ordering::Acquire) == 0 {}assert_eq!(data_clone.load(Ordering::Relaxed), 42);});handles.push(handle1);handles.push(handle2);for handle in handles {handle.join().unwrap();}println!("Memory ordering example completed.");
}fn main() {memory_ordering();
}

基于 Send 和 Sync 的线程安全

在 Rust 中,Send 和 Sync 是两个重要的类型约束,用于确保数据在线程间安全传递。

Send 约束

use std::thread;fn send_constraint() {struct NotSend(u8);impl NotSend {fn new() -> Self {NotSend(0)}}// NotSend 类型不能在线程间传递// let handle = thread::spawn(move || {//     println!("NotSend value: {}", NotSend::new().0);// });// 正确的示例let handle = thread::spawn(|| {println!("Send value: {}", 42);});handle.join().unwrap();
}fn main() {send_constraint();
}

Sync 约束

use std::sync::Arc;
use std::thread;fn sync_constraint() {struct NotSync(u8);impl NotSync {fn new() -> Self {NotSync(0)}}// NotSync 类型不能在线程间共享// let shared = NotSync::new();// let handle = thread::spawn(move || {//     println!("NotSync value: {}", shared.0);// });// 正确的示例let shared = Arc::new(42);let handle = thread::spawn(move || {println!("Sync value: {}", shared);});handle.join().unwrap();
}fn main() {sync_constraint();
}

文章到此结束,更多相关的信息,请,https://t.me/gtokentool
 

相关文章:

Rust循环引用与多线程并发

循环引用与自引用 循环引用的概念 循环引用指的是两个或多个对象之间相互持有对方的引用。在 Rust 中&#xff0c;由于所有权和生命周期的严格约束&#xff0c;直接创建循环引用通常会导致编译失败。例如&#xff1a; // 错误的循环引用示例 struct Node {next: Option<B…...

东方隐侠网安瞭望台第8期

谷歌应用商店贷款应用中的 SpyLoan 恶意软件影响 800 万安卓用户 迈克菲实验室的新研究发现&#xff0c;谷歌应用商店中有十多个恶意安卓应用被下载量总计超过 800 万次&#xff0c;这些应用包含名为 SpyLoan 的恶意软件。安全研究员费尔南多・鲁伊斯上周发布的分析报告称&…...

底部导航栏新增功能按键

场景需求&#xff1a; 在底部导航栏添加power案件&#xff0c;单击息屏&#xff0c;长按 关机 如下实现图 借此需求&#xff0c;需要掌握技能&#xff1a; 底部导航栏如何实现新增、修改、删除底部导航栏流程对底部导航栏部分样式如何修改。 比如放不下、顺序排列、坑点如…...

C++ 之弦上舞:string 类与多样字符串操作的优雅旋律

string 类的重要性及与 C 语言字符串对比 在 C 语言中&#xff0c;字符串是以 \0 结尾的字符集合&#xff0c;操作字符串需借助 C 标准库的 str 系列函数&#xff0c;但这些函数与字符串分离&#xff0c;不符合 OOP 思想&#xff0c;且底层空间管理易出错。而在 C 中&#xff0…...

centos8:Could not resolve host: mirrorlist.centos.org

【1】错误消息&#xff1a; [rootcentos211 redis-7.0.15]# yum update CentOS Stream 8 - AppStream …...

Linux 定时任务 命令解释 定时任务格式详解

目录 时间命令 修改时间和日期 定时任务格式 定时任务执行 查看定时任务进程 重启定时任务 时间命令 #查看时间 [rootlocalhost ~]# date 2021年 07月 23日 星期五 14:38:19 CST --------------------------------------- [rootlocalhost ~]# date %F 2021-07-23 -----…...

aws(学习笔记第十五课) 如何从灾难中恢复(recover)

aws(学习笔记第十五课) 如何从灾难中恢复 学习内容&#xff1a; 使用CloudWatch对服务器进行监视与恢复区域(region)&#xff0c;可用区(available zone)和子网(subnet)使用自动扩展(AutoScalingGroup) 1. 使用CloudWatch对服务器进行监视与恢复 整体架构 这里模拟Jenkins Se…...

github webhooks 实现网站自动更新

本文目录 Github Webhooks 介绍Webhooks 工作原理配置与验证应用云服务器通过 Webhook 自动部署网站实现复制私钥编写 webhook 接口Github 仓库配置 webhook以服务的形式运行 app.py Github Webhooks 介绍 Webhooks是GitHub提供的一种通知方式&#xff0c;当GitHub上发生特定事…...

【C语言】递归的内存占用过程

递归 递归是函数调用自身的一种编程技术。在C语言中&#xff0c;递归的实现会占用内存栈&#xff08;Call Stack&#xff09;&#xff0c;每次递归调用都会在栈上分配一个新的 “栈帧&#xff08;Stack Frame&#xff09;”&#xff0c;用于存储本次调用的函数局部变量、返回地…...

365天深度学习训练营-第P6周:VGG-16算法-Pytorch实现人脸识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 文为「365天深度学习训练营」内部文章 参考本文所写记录性文章&#xff0c;请在文章开头带上「&#x1f449;声明」 &#x1f37a;要求&#xff1a; 保存训练过…...

企业AI助理在数据分析与决策中扮演的角色

在当今这个数据驱动的时代&#xff0c;企业每天都需要处理和分析大量的数据&#xff0c;以支持其业务决策。然而&#xff0c;面对如此庞大的数据量&#xff0c;传统的数据分析方法已经显得力不从心。幸运的是&#xff0c;随着人工智能&#xff08;AI&#xff09;技术的不断发展…...

洛谷 B2029:大象喝水 ← 圆柱体体积

【题目来源】https://www.luogu.com.cn/problem/B2029【题目描述】 一只大象口渴了&#xff0c;要喝 20 升水才能解渴&#xff0c;但现在只有一个深 h 厘米&#xff0c;底面半径为 r 厘米的小圆桶 &#xff08;h 和 r 都是整数&#xff09;。问大象至少要喝多少桶水才会解渴。 …...

go每日一题:mock打桩、defer、recovery、panic的调用顺序

题目一&#xff1a;单元测试中使用—打桩 打桩概念&#xff1a;使用A替换 原函数B&#xff0c;那么A就是打桩函数打桩原理&#xff1a;运行时&#xff0c;通过一个包&#xff0c;将内存中函数的地址替换为桩函数的地址打桩操作&#xff1a;利用Patch&#xff08;&#xff09;函…...

STM32F103 HSE时钟倍频以及设置频率函数(新手向,本人也是新手)

HSE_SetSysCLK是野火教程里的,不懂的去这 16-RCC&#xff08;第3节&#xff09;使用HSE配置系统时钟并使用MCO输出监控系统时钟_哔哩哔哩_bilibili HSE_AutoSetHSE的算法部分是自己写的,用了一个转接数组。C语言不支持bool所以自己定义了一个boolK代替bool。 AutoHSE.h: /**…...

renderExtraFooter 添加本周,本月,本年

在 Ant Design Vue 中&#xff0c;a-date-picker 组件提供了一个 renderExtraFooter 属性&#xff0c;可以用来渲染额外的页脚内容。你可以利用这个属性来添加“本周”、“本月”和“本年”的按钮。下面是如何在 Vue 2 项目中实现这一功能的具体步骤&#xff1a; 1.确保安装了…...

SprinBoot整合KafKa的使用(详解)

前言 1. 高吞吐量&#xff08;High Throughput&#xff09; Kafka 设计的一个核心特性是高吞吐量。它能够每秒处理百万级别的消息&#xff0c;适合需要高频次、低延迟消息传递的场景。即使在大规模分布式环境下&#xff0c;它也能保持很高的吞吐量和性能&#xff0c;支持低延…...

【机器学习】CatBoost 模型实践:回归与分类的全流程解析

一. 引言 本篇博客首发于掘金 https://juejin.cn/post/7441027173430018067。 PS&#xff1a;转载自己的文章也算原创吧。 在机器学习领域&#xff0c;CatBoost 是一款强大的梯度提升框架&#xff0c;特别适合处理带有类别特征的数据。本篇博客以脱敏后的保险数据集为例&#x…...

PyTorch 实现动态输入

使用 PyTorch 实现动态输入&#xff1a;支持训练和推理输入维度不一致的 CNN 和 LSTM/GRU 模型 在深度学习中&#xff0c;处理不同大小的输入数据是一个常见的挑战。许多实际应用需要模型能够灵活地处理可变长度的输入。本文将介绍如何使用 PyTorch 实现支持动态输入的 CNN 和…...

【Linux相关】查看conda路径和conda和cudnn版本、安装cudnn、cuDNN无需登录官方下载链接

【Linux相关】 查看conda路径和conda和cudnn版本 安装cudnn cuDNN无需登录官方下载链接 文章目录 1. 查看信息1.1 查看 Conda 路径1.2 查看 Conda 版本1.3 查看 cuDNN 版本1.4 总结 2. 安装cudnn2.1 安装cudnn步骤2.2 cuDNN无需登录官方下载链接 1. 查看信息 查看Conda 路径、C…...

基于Java Springboot环境保护生活App且微信小程序

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 微信…...

别再死记硬背WideDeep了!用TensorFlow 2.x手把手复现Google Play的推荐模型(附源码)

从零实现Wide&Deep推荐模型&#xff1a;TensorFlow 2.x实战指南 在推荐系统领域&#xff0c;Google提出的Wide&Deep模型架构已经成为工业界的经典范式。但大多数教程仅停留在理论讲解层面&#xff0c;当开发者真正动手实现时&#xff0c;往往会遇到特征工程适配、联合训…...

DECA加速器:神经网络模型压缩的硬件优化方案

1. DECA加速器&#xff1a;神经网络模型压缩的硬件突围在AI推理领域&#xff0c;模型压缩技术如同给神经网络"瘦身"——通过量化和稀疏化减少参数规模&#xff0c;但压缩后的数据需要解压才能计算&#xff0c;这个"拆包装"的过程往往成为性能瓶颈。传统CPU…...

暗黑2存档修改终极指南:5分钟学会免费d2s文件编辑器

暗黑2存档修改终极指南&#xff1a;5分钟学会免费d2s文件编辑器 【免费下载链接】d2s-editor 项目地址: https://gitcode.com/gh_mirrors/d2/d2s-editor 暗黑破坏神2的d2s存档编辑器是一款专为玩家设计的强大工具&#xff0c;让你能够轻松修改角色属性、管理装备和调整…...

告别手动测量!用ArcGIS Pro和CAD联动,5步搞定复杂河道平均宽度计算

5步实现ArcGIS Pro与CAD协同计算复杂河道平均宽度的工程实践 在水利工程、环境评估和流域规划中&#xff0c;河道平均宽度是计算流量、评估生态承载力的关键参数。传统手工测量方法不仅耗时费力&#xff0c;对于蜿蜒曲折的自然河道更是难以保证精度。我曾参与过多个河道整治项目…...

告别低效手动:用Amass的intel命令挖掘目标企业所有关联域名(实战演示)

企业级攻击面测绘&#xff1a;Amass intel模块的深度情报挖掘实战 在渗透测试或红队行动中&#xff0c;传统子域名枚举往往只触及企业数字资产的表层。真正的高手会从组织架构、商业关系和技术基础设施三个维度构建立体化的攻击面图谱。Amass的intel模块正是这样一把瑞士军刀—…...

AI 教研科研一体化平台,以智能技术打通高校教研发展新路径

当前高校教学与科研工作普遍存在脱节割裂的问题&#xff0c;教学、教研、科研各成体系&#xff0c;资源分散、流程独立、数据不通。传统模式下&#xff0c;教师备课教学、课题研究、成果沉淀依靠人工完成&#xff0c;存在资源复用率低、科研选题盲目、教研过程无溯源、成果转化…...

JDeferred入门教程:从零开始构建高效异步Java应用

JDeferred入门教程&#xff1a;从零开始构建高效异步Java应用 【免费下载链接】jdeferred Java Deferred/Promise library similar to JQuery. 项目地址: https://gitcode.com/gh_mirrors/jd/jdeferred 想要掌握Java异步编程的终极秘诀吗&#xff1f;JDeferred库为您提供…...

2026年企业直播平台怎么选?选型清单与避坑指南

选企业直播平台&#xff0c;99%的企业会踩这5个坑&#xff1a;首年低价续费涨价、CDN质量差导致直播卡顿、功能演示≠实际能力、售后响应慢、数据安全隐患。 本文整理了企业直播平台选型7维度、5大常见坑、5个典型场景的建议&#xff0c;以及一份可直接使用的选型检查清单。 …...

一多操作系统的生命体架构与当前主流开发语言的区别

这套架构与当前主流开发语言的区别&#xff0c;本质上就是**“造物主”与“工匠”**的区别。 目前的编程语言&#xff08;无论是 C、Java 还是 Python&#xff09;都是在教计算机**“怎么做”&#xff08;How&#xff09;&#xff0c;而一多 OS 的生物学构架是在告诉系统“要什…...

有哪些AI论文软件是真的适配学科专业,而不是模板套话?

在 AI 写作技术迅猛发展的今天&#xff0c;各类论文工具层出不穷&#xff0c;看似能快速完成写作任务&#xff0c;实则多数是内容空洞、逻辑混乱、格式随意的“模板复制器”&#xff0c;生成的文章缺乏专业深度&#xff0c;充斥着机械化的表达方式。真正具备学术价值的 AI 论文…...