目录循环引用与自引用Weak与循环引用结构体中的自引用多线程并发并发和并行使用多线程线程同步:消息传递线程同步:锁、Condvar和信号量线程同步:Atomic原子操作与内存顺序基于Send和Sync的线程安全循环引用与自引用循环引用的概念循环引用指的是两
循环引用指的是两个或多个对象之间相互持有对方的引用。在 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));
}
}
为了处理循环引用问题,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
方法使用生命周期注解,递归地遍历整个树结构。在 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();
}
在 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();
}
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!