Rust中的并发与多线程:安全编程

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Rust中的并发与多线程:编写安全的并行代码



Rust是少数能在编译阶段解决数据竞争(data races)问题的语言之一。得益于所有权(ownership)和借用(borrowing)系统,Rust中的并发代码不仅快速,而且安全。本文将讲解Rust多线程的基础知识:创建线程、通过通道和互斥锁进行数据交换,并介绍"Fearless Concurrency"模型。



1. 多线程基础:std::thread



Rust通过std::thread模块提供内置的线程支持。可以使用thread::spawn函数创建新线程,该函数接受一个闭包。



use std::thread;use std::time::Duration;

fn main() { let handle = thread::spawn(|| { for i in 1..10 { println!("线程: {}", i); thread::sleep(Duration::from_millis(1)); } });

for i in 1..5 { println!("主线程: {}", i); thread::sleep(Duration::from_millis(1)); }

handle.join().unwrap(); // 等待线程结束}


join()方法会阻塞主线程,直到子线程执行完毕。如果没有它,程序可能会在线程执行完之前就结束。



2. 线程间数据传输:通道(mpsc)



在Rust中,线程间消息传递使用多生产者,单消费者通道(mpsc — multiple producer, single consumer)模型。这通过std::sync::mpsc模块实现。



use std::sync::mpsc;use std::thread;

fn main() { let (tx, rx) = mpsc::channel();

thread::spawn(move || { let val = String::from("来自线程的问候!"); tx.send(val).unwrap(); // val 已经被移动,不能再使用 });

let received = rx.recv().unwrap(); println!("收到: {}", received);}


注意闭包中的move关键字——它将变量tx的所有权转移到新线程中。send()方法返回一个Result,如果接收端已关闭,则可能为Err。



要创建多个生产者,可以克隆tx:



let (tx, rx) = mpsc::channel();let tx1 = tx.clone();

thread::spawn(move || { tx.send("消息 1").unwrap();});

thread::spawn(move || { tx1.send("消息 2").unwrap();});

for received in rx { println!("收到: {}", received);}


3. 共享内存:Mutex和Arc



通道适合数据传输,但有时需要在线程间共享状态。这时使用Mutex(互斥锁)配合Arc(原子引用计数)。



use std::sync::{Arc, Mutex};use std::thread;

fn main() { let counter = Arc::new(Mutex::new(0)); let mut handles = vec![];

for _ in 0..10 { let counter = Arc::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.lock().unwrap());}


为什么用Arc而不是Rc?普通的Rc不是线程安全的,因为它的引用计数不是原子的。Arc使用原子操作,使其在多线程环境下安全。



重要:Mutex在调用lock()时会阻塞线程。离开作用域后,锁会自动释放(得益于Drop trait)。



4. Fearless Concurrency模型与Send/Sy

博客

书籍推荐