Класс Condvar
Класс Condvar (condition variable) представляет
собой примитив синхронизации, который позволяет
блокировать выполнение одного или нескольких потоков
до тех пор, пока другой поток не уведомит их о
наступлении определённого события. Условная переменная
всегда используется совместно с мьютексом
Mutex, который защищает общие данные.
Метод new создаёт новую условную переменную,
метод wait блокирует текущий поток и
освобождает мьютекс, а методы notify_one и
notify_all пробуждают один или все
ожидающие потоки соответственно.
Синтаксис
use std::sync::{Condvar, Mutex};
let pair = (Mutex::new(value), Condvar::new());
Пример
Давайте создадим условную переменную вместе с мьютексом и посмотрим на базовое ожидание и уведомление:
use std::sync::{Arc, Condvar, Mutex};
use std::thread;
fn main()
{
let pair = Arc::new((Mutex::new(false), Condvar::new()));
let pair2 = Arc::clone(&pair);
let handle = thread::spawn(move || {
let (lock, cvar) = &*pair2;
let mut started = lock.lock().unwrap();
*started = true;
cvar.notify_one();
});
let (lock, cvar) = &*pair;
let mut started = lock.lock().unwrap();
while !*started {
started = cvar.wait(started).unwrap();
}
handle.join().unwrap();
println!("{}", *started);
}
Результат выполнения кода:
true
Пример
Давайте используем метод wait_timeout,
чтобы поток не ждал уведомления бесконечно:
use std::sync::{Arc, Condvar, Mutex};
use std::time::Duration;
fn main()
{
let pair = Arc::new((Mutex::new(false), Condvar::new()));
let (lock, cvar) = &*pair;
let started = lock.lock().unwrap();
let (res, timeout) = cvar
.wait_timeout(started, Duration::from_millis(100))
.unwrap();
println!("{}", *res);
println!("{}", timeout.timed_out());
}
Результат выполнения кода:
false
true
Пример
Давайте используем метод notify_all,
чтобы разбудить сразу несколько ожидающих потоков:
use std::sync::{Arc, Condvar, Mutex};
use std::thread;
fn main()
{
let pair = Arc::new((Mutex::new(0), Condvar::new()));
let mut handles = vec![];
for _ in 0..3 {
let pair = Arc::clone(&pair);
handles.push(thread::spawn(move || {
let (lock, cvar) = &*pair;
let mut count = lock.lock().unwrap();
while *count == 0 {
count = cvar.wait(count).unwrap();
}
*count
}));
}
let (lock, cvar) = &*pair;
let mut count = lock.lock().unwrap();
*count = 42;
cvar.notify_all();
drop(count);
for handle in handles {
println!("{}", handle.join().unwrap());
}
}
Результат выполнения кода:
42
42
42
Смотрите также
-
метод
new,
который создаёт новую условную переменную -
метод
wait,
который блокирует поток до получения уведомления -
метод
wait_timeout,
который блокирует поток на указанное время -
метод
notify_one,
который пробуждает один ожидающий поток