- 구조체 Condvar는 Condition Variable의 약자로, 이벤트가 발생할 때까지 스레드를 차단하여 CPU 시간을 소비하지 않도록 하기 위해 사용한다. 조건 변수는 일반적으로 boolean predicate, 뮤텍스와 함께 사용된다.
- 스레드를 차단해야 한다고 판단하기 전에 뮤텍스 내에서 항상 조건을 검증한다.
- 이 모듈의 함수는 현재 실행 중인 스레드를 차단한다. 동일한 조건 변수에 여러 뮤텍스를 사용하려고 시도하면 런타임 패닉이 발생할 수 있다.
예제
use std::sync::{Arc, Mutex, Condvar};use std::thread;
let pair = Arc::new((Mutex::new(false), Condvar::new()));let pair2 = Arc::clone(&pair);
// Inside of our lock, spawn a new thread, and then wait for it to start.thread::spawn(move|| { let (lock, cvar) = &*pair2; let mut started = lock.lock().unwrap(); *started = true; // We notify the condvar that the value has changed. cvar.notify_one();});
// Wait for the thread to start up.let (lock, cvar) = &*pair;let mut started = lock.lock().unwrap();while !*started { started = cvar.wait(started).unwrap();}
함수
new()
pub const fn new() -> Condvar
새로운 Condvar를 생성한다.
wait()
pub fn wait<'a, T>( &self, guard: MutexGuard<'a, T>) -> LockResult<MutexGuard<'a, T>>
현재 조건 변수가 알림을 받을 때까지 현재 스레드를 블록한다.
이 함수는 뮤텍스를 잠그고 현재 스레드를 차단한다. 뮤텍스가 해제된 후 notify_one
또는 notify_all
를 호출하면 스레드를 깨울 수 있다. 함수 호출이 반환되면 지정된 락이 다시 획득된다.
스레드가 락을 다시 획득할 때 뮤텍스가 손상되어있는 경우 오류를 반환한다.
예제
use std::sync::{Arc, Mutex, Condvar};use std::thread;
let pair = Arc::new((Mutex::new(false), Condvar::new()));let pair2 = Arc::clone(&pair);
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();// 내부의 값이 `false`인 동안 기다린다.while !*started { started = cvar.wait(started).unwrap();}
wait_while()
pub fn wait_while<'a, T, F>( &self, guard: MutexGuard<'a, T>, condition: F) -> LockResult<MutexGuard<'a, T>>where F: FnMut(&mut T) -> bool,
현재 스레드가 알림을 받아 조건을 검증했을 때 그 결과가 false일 때까지 현재 스레드를 차단한다. 다시말해, 스레드를 차단했다가 알림을 받아 조건을 검증한 결과가 false일 때 차단을 해제한다.
이 함수도 wait()
과 동일하게 뮤텍스를 잠그고 현재 스레드를 차단한다.
예제
use std::sync::{Arc, Mutex, Condvar};use std::thread;
let pair = Arc::new((Mutex::new(true), Condvar::new()));let pair2 = Arc::clone(&pair);
thread::spawn(move|| { let (lock, cvar) = &*pair2; let mut pending = lock.lock().unwrap(); *pending = false; // 값이 변경되었음을 조건 변수에 알린다. cvar.notify_one();});
// 스레드가 시작되기를 기다란다.let (lock, cvar) = &*pair;// 내부의 값이 `true`인 동안 기다린다.let _guard = cvar.wait_while(lock.lock().unwrap(), |pending| { *pending }).unwrap();
wait_timeout()
pub fn wait_timeout<'a, T>( &self, guard: MutexGuard<'a, T>, dur: Duration) -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)>
이 조건 변수에 대한 알림을 기다리되, dur 파라미터로 지정한 기간만큼 차단한 후 타임아웃을 해제한다. 선점(preemption) 또는 플랫폼 간의 차이 등으로 인해 대기 시간이 정확히 dur이 되지 않을 수 있기 때문에, 정확한 기간이 보장되어야 하는 경우에는 적절하지 않다.
반환된 WaitTimeoutResult 값은 타임아웃이 경과했는지 여부를 나타낸다.
notify_one()
하나의 차단된 스레드를 깨운다.
만약 이 조건 변수에 차단된 스레드가 있다면, 해당 스레드는 wait 또는 wait_timeout 호출로부터 깨어날 것이다.
use std::sync::{Arc, Mutex, Condvar};use std::thread;
let pair = Arc::new((Mutex::new(false), Condvar::new()));let pair2 = Arc::clone(&pair);
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();// Mutex<bool> 내부의 값이 `false`인 동안 기다린다.while !*started { started = cvar.wait(started).unwrap();}
notify_all()
이 condvar에 대기 중인 모든 차단된 스레드를 깨운다.
이 메서드는 조건 변수에 대기 중인 현재 모든 대기 스레드가 깨어나도록 보장한다.
use std::sync::{Arc, Mutex, Condvar};use std::thread;
let pair = Arc::new((Mutex::new(false), Condvar::new()));let pair2 = Arc::clone(&pair);
thread::spawn(move|| { let (lock, cvar) = &*pair2; let mut started = lock.lock().unwrap(); *started = true; // 값이 변경되었음을 알린다. cvar.notify_all();});
// 스레드가 시작될 때까지 기다린다.let (lock, cvar) = &*pair;let mut started = lock.lock().unwrap();// Mutex<bool> 내부의 값이 `false`인 동안 기다린다.while !*started { started = cvar.wait(started).unwrap();}
참고