- 条件变量(
Condvar
)与互斥锁(Mutex
)配合原理
- 在Rust中,
Condvar
本身不能直接保护数据,它需要与Mutex
一起使用。Mutex
用于保护共享数据,确保在同一时间只有一个线程可以访问这些数据。而Condvar
则用于线程间的同步,允许线程等待某个条件满足后被唤醒。
- 当一个线程需要等待某个条件时,它首先获取
Mutex
的锁,然后调用Condvar
的wait
方法。wait
方法会暂时释放Mutex
的锁,让其他线程有机会修改共享数据。同时,该线程会进入等待状态。当另一个线程修改了共享数据并满足等待线程所期望的条件时,它可以获取Mutex
的锁(如果尚未获取),然后调用Condvar
的notify
系列方法(如notify_one
或notify_all
)来唤醒等待的线程。被唤醒的线程会重新获取Mutex
的锁,然后继续执行。
wait
方法的使用场景及作用
- 使用场景:常用于线程需要等待某个条件满足才能继续执行的场景。例如,在生产者 - 消费者模型中,消费者线程需要等待生产者线程生产出数据后才能消费。
- 作用:使当前线程进入等待状态,并暂时释放它持有的
Mutex
锁。这样其他线程就可以获取锁并修改共享数据。当被唤醒时,线程会重新获取Mutex
锁,然后继续执行。
- 示例:
use std::sync::{Arc, Condvar, Mutex};
use std::thread;
fn main() {
let data = Arc::new((Mutex::new(0), Condvar::new()));
let data_clone = data.clone();
let consumer = thread::spawn(move || {
let (lock, cvar) = &*data_clone;
let mut data = lock.lock().unwrap();
while *data == 0 {
data = cvar.wait(data).unwrap();
}
println!("Consumer got data: {}", *data);
});
let producer = thread::spawn(move || {
let (lock, cvar) = &*data;
let mut data = lock.lock().unwrap();
*data = 42;
cvar.notify_one();
});
consumer.join().unwrap();
producer.join().unwrap();
}
- 在这个例子中,消费者线程通过
wait
方法等待数据不为0。当生产者线程修改数据并调用notify_one
后,消费者线程被唤醒,重新获取锁并继续执行。
notify
方法的使用场景及作用
notify_one
:
- 使用场景:当只有一个等待线程需要被唤醒时使用。例如,在单生产者 - 单消费者模型中,生产者生产数据后,只需要唤醒一个消费者线程。
- 作用:随机唤醒一个正在等待该
Condvar
的线程。
notify_all
:
- 使用场景:当所有等待线程都需要被唤醒时使用。例如,在服务器处理一批任务后,所有等待结果的客户端线程都需要被唤醒。
- 作用:唤醒所有正在等待该
Condvar
的线程。所有被唤醒的线程会竞争获取Mutex
锁,获取到锁的线程会继续执行。