面试题答案
一键面试use std::sync::{Arc, Mutex, Condvar, mpsc};
use std::thread;
fn main() {
let data = Arc::new(Mutex::new(Vec::new()));
let cond = Arc::new(Condvar::new());
let (tx, rx) = mpsc::channel();
// T1线程
let t1 = thread::spawn({
let data = data.clone();
let cond = cond.clone();
let tx = tx.clone();
move || {
let mut data = data.lock().unwrap();
data.push(1);
data.push(2);
data.push(3);
println!("T1: 初始化添加操作完成");
// 通知其他线程初始化完成
cond.notify_all();
// 发送信号给T2和T3可以开始执行
tx.send(()).unwrap();
}
});
// T2线程
let t2 = thread::spawn({
let data = data.clone();
let cond = cond.clone();
let rx = rx.clone();
move || {
let mut data = data.lock().unwrap();
// 等待T1初始化完成
data = cond.wait(data).unwrap();
// 等待T1发送的开始信号
rx.recv().unwrap();
if let Some(_) = data.pop() {
println!("T2: 删除操作完成");
}
}
});
// T3线程
let t3 = thread::spawn({
let data = data.clone();
let cond = cond.clone();
let rx = rx.clone();
move || {
let mut data = data.lock().unwrap();
// 等待T1初始化完成
data = cond.wait(data).unwrap();
// 等待T1发送的开始信号
rx.recv().unwrap();
data.sort();
println!("T3: 排序操作完成");
}
});
t1.join().unwrap();
t2.join().unwrap();
t3.join().unwrap();
}
happens - before关系保证说明:
- T1在T2和T3之前完成初始化添加操作:
- 使用
Condvar
来实现。T2和T3在获取Mutex
锁后,调用cond.wait
进入等待状态,直到T1调用cond.notify_all
通知它们。这确保了T1的初始化添加操作在T2和T3的操作之前完成,因为wait
会释放锁并阻塞线程,直到被通知。这里cond.wait
和cond.notify_all
之间存在一种隐式的同步关系,即notify_all
之前的所有操作(T1的添加操作)都在wait
返回后的操作(T2和T3的操作)之前发生。
- 使用
- T2的删除操作在T3的排序操作之前:
- 通过
mpsc
通道来实现。T1在完成初始化添加操作后,通过tx.send(())
发送一个信号。T2和T3都通过rx.recv()
接收这个信号,因为通道是先进先出的,所以T2会先接收到信号并执行删除操作,然后T3才会接收到信号执行排序操作。这种基于通道的同步机制保证了T2的删除操作在T3的排序操作之前从逻辑数据一致性角度发生。
- 通过
以上代码通过Condvar
和mpsc
通道实现了所需的线程同步和happens - before关系。