当前位置: 首页 > 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 微信…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

Android Wi-Fi 连接失败日志分析

1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分&#xff1a; 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析&#xff1a; CTR…...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank&#xff1f;由于时间太久&#xff0c;我真忘记了。搜搜发现&#xff0c;还真有人和我一样。见下面的链接&#xff1a;https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

MongoDB学习和应用(高效的非关系型数据库)

一丶 MongoDB简介 对于社交类软件的功能&#xff0c;我们需要对它的功能特点进行分析&#xff1a; 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具&#xff1a; mysql&#xff1a;关系型数据库&am…...

工程地质软件市场:发展现状、趋势与策略建议

一、引言 在工程建设领域&#xff0c;准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具&#xff0c;正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)

在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马&#xff08;服务器方面的&#xff09;的原理&#xff0c;连接&#xff0c;以及各种木马及连接工具的分享 文件木马&#xff1a;https://w…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化

缓存架构 代码结构 代码详情 功能点&#xff1a; 多级缓存&#xff0c;先查本地缓存&#xff0c;再查Redis&#xff0c;最后才查数据库热点数据重建逻辑使用分布式锁&#xff0c;二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...