通知
通知
看是简单的通知,在编程时也需要注意以下几点:
- 通知必然是因为有等待,所以通知和等待几乎都是成对出现的,比如
std::sync::Condvar::wait
和std::sync::Condvar::notify_one
,std::sync::Condvar::notify_all
。 - 等待所使用的对象,与通知使用的对象是同一个对象,从而该对象需要在多个线程之间共享,参见下面的例子。
- 除了
Condvar
之外,其实锁也是具有自动通知功能的,当持有锁的线程释放锁的时候,等待锁的线程就会自动被唤醒,以抢占锁。关于锁的介绍,在下面有详解。 - 通过条件变量和锁,还可以构建更加复杂的自动通知方式,比如
std::sync::Barrier
。 - 通知也可以是 1:1 的,也可以是 1:N 的,
Condvar
可以控制通知一个还是 N 个,而锁则不能控制,只要释放锁,所有等待锁的其他线程都会同时醒来,而不是只有最先等待的线程。
use std::sync::{Arc, Mutex, Condvar};
use std::thread;
fn main() {
let pair = Arc::new((Mutex::new(false), Condvar::new()));
let pair2 = pair.clone();
// 创建一个新线程
thread::spawn(move|| {
let &(ref lock, ref cvar) = &*pair2;
let mut started = lock.lock().unwrap();
*started = true;
cvar.notify_one();
println!("notify main thread");
});
// 等待新线程先运行
let &(ref lock, ref cvar) = &*pair;
let mut started = lock.lock().unwrap();
while !*started {
println!("before wait");
started = cvar.wait(started).unwrap();
println!("after wait");
}
}
before wait
notify main thread
after wait
这个例子展示了如何通过条件变量和锁来控制新建线程和主线程的同步,让主线程等待新建线程执行后,才能继续执行。从结果来看,功能上是实现了。对于上面这个例子,还有下面几点需要说明:
Mutex
是 Rust 中的一种锁。Condvar
需要和Mutex
一同使用,因为有Mutex
保护,Condvar
并发才是安全的。Mutex::lock
方法返回的是一个MutexGuard
,在离开作用域的时候,自动销毁,从而自动释放锁,从而避免锁没有释放的问题。Condvar
在等待时,时会释放锁的,被通知唤醒时,会重新获得锁,从而保证并发安全。