面试题答案
一键面试条件变量的使用场景
在Rust中,条件变量通常用于以下多线程同步场景:
- 生产者 - 消费者模型:生产者线程生产数据并将其放入共享队列,消费者线程从队列中取出数据进行处理。当队列为空时,消费者线程需要等待,直到有新的数据被生产出来,此时就可以使用条件变量。
- 资源获取等待:当一个线程需要获取某个资源,但该资源当前不可用时,线程可以等待,直到资源可用。例如,连接池中的连接数量有限,当所有连接都被占用时,新的请求需要等待直到有连接被释放。
示例代码
use std::sync::{Arc, Condvar, Mutex};
use std::thread;
fn main() {
let pair = Arc::new((Mutex::new(false), Condvar::new()));
let pair2 = pair.clone();
thread::spawn(move || {
let (lock, cvar) = &*pair2;
let mut started = lock.lock().unwrap();
*started = true;
println!("Notifying the waiting thread...");
cvar.notify_one();
});
let (lock, cvar) = &*pair;
let mut started = lock.lock().unwrap();
while!*started {
started = cvar.wait(started).unwrap();
}
println!("The waiting thread has been notified!");
}
关键部分解释
- 创建条件变量和互斥锁:
let pair = Arc::new((Mutex::new(false), Condvar::new()));
这里通过Arc
(原子引用计数)来创建一个包含互斥锁Mutex
和条件变量Condvar
的元组。Mutex
用于保护共享数据,Condvar
用于线程间的通知和等待。
- 线程1(通知线程):
thread::spawn(move || {
let (lock, cvar) = &*pair2;
let mut started = lock.lock().unwrap();
*started = true;
println!("Notifying the waiting thread...");
cvar.notify_one();
});
这个线程获取锁并修改共享状态started
为true
,然后调用cvar.notify_one()
通知等待在条件变量上的一个线程。
- 线程2(等待线程):
let (lock, cvar) = &*pair;
let mut started = lock.lock().unwrap();
while!*started {
started = cvar.wait(started).unwrap();
}
println!("The waiting thread has been notified!");
这个线程获取锁并检查共享状态started
。如果started
为false
,则调用cvar.wait(started)
进入等待状态。wait
方法会释放锁并阻塞线程,直到收到通知。当收到通知后,wait
方法重新获取锁并返回被修改后的锁的所有权,线程继续检查started
状态,直到started
为true
。