面试题答案
一键面试use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread;
use rand::Rng;
fn main() {
let (tx, rx): (Sender<i32>, Receiver<i32>) = channel();
let producer = thread::spawn(move || {
let mut rng = rand::thread_rng();
loop {
let num = rng.gen_range(1..100);
if let Err(e) = tx.send(num) {
eprintln!("Producer error: {:?}", e);
break;
}
}
});
let consumer = thread::spawn(move || {
loop {
match rx.recv() {
Ok(num) => {
let square = num * num;
println!("Square of {} is {}", num, square);
}
Err(e) => {
eprintln!("Consumer error: {:?}", e);
break;
}
}
}
});
producer.join().unwrap();
drop(tx);
consumer.join().unwrap();
}
Rust内存安全机制在该模型中的作用
-
所有权系统:Rust 的所有权系统确保每个值都有一个唯一的所有者,在生产者 - 消费者模型中,通道发送和接收数据时,所有权会转移。例如,
tx.send(num)
将num
的所有权转移到通道,保证了同一时间只有一个线程可以访问该数据,避免数据竞争。 -
借用规则:借用规则规定在同一时间,要么只能有一个可变借用(可变引用),要么可以有多个不可变借用(不可变引用),但不能同时存在可变和不可变借用。在这个模型中,没有显式使用借用,但它从底层保证了通道内部数据的访问一致性,防止因错误的引用导致内存安全问题。
-
生命周期:Rust 要求所有引用都有明确的生命周期,这确保了引用不会指向已经释放的内存。在生产者 - 消费者模型中,通道的生命周期和线程的生命周期紧密相关,例如,当生产者线程结束后,通过
drop(tx)
主动关闭通道,消费者线程通过rx.recv()
的返回值得知通道关闭,避免了消费者继续从已关闭通道接收数据导致的未定义行为。 -
线程安全:Rust 的类型系统和所有权系统使得在多线程环境下编写安全代码更容易。
std::sync::mpsc
模块提供的通道本身就是线程安全的,通过所有权转移和借用规则,在多线程间传递数据时保证了内存安全,避免了死锁和数据竞争问题。