조건 변수

조건 변수 안전 계약

condition_variable은 스레드를 깨우는 도구라는 설명만으로는 부족하다. 공유 상태를 mutex로 보호하고, wait는 predicate를 반복 확인하며, notify는 상태 변경 뒤 호출해야 spurious wakeup과 lost wakeup을 피할 수 있다.

01

공유 상태 정의

대기 조건이 되는 queue, flag, count를 하나의 mutex로 보호한다.

조건 변수 자체가 상태를 저장하지 않는다
02

락 획득

consumer는 unique_lock으로 mutex를 잡고 predicate를 확인한다.

condition_variable wait에는 unique_lock이 필요하다
03

반복 대기

wait(lock, predicate)를 사용해 깨어난 뒤 조건을 다시 확인한다.

spurious wakeup을 전제로 코드를 짠다
04

상태 변경 후 알림

producer는 락 안에서 queue에 넣거나 flag를 바꾸고 notify_one 또는 notify_all을 호출한다.

상태 없는 notify는 잃어버릴 수 있다
05

종료와 timeout

작업 종료 flag와 wait_for timeout을 설계해 영원히 기다리는 스레드를 막는다.

종료 조건도 predicate에 포함한다
predicate
실제 대기 조건 깨어나야 하는 이유를 bool 조건으로 표현하고 반복 확인한다.
if가 아니라 while 의미다
notify_one
대기자 하나 깨움 작업 하나를 소비할 스레드 하나만 필요할 때 쓴다.
대기자가 없으면 저장되지 않는다
notify_all
모든 대기자 깨움 종료 flag나 여러 조건 변화처럼 모두 확인해야 할 때 쓴다.
thundering herd를 조심한다
wait_for
시간 제한 대기 외부 이벤트가 없을 때 영원히 멈추지 않도록 timeout을 둔다.
timeout 후에도 predicate를 확인한다

동시성 확인

predicate 사용 wait가 predicate 형태이거나 while 루프로 조건을 다시 확인하는지 본다.
상태 보호 대기 조건에 쓰는 변수와 queue가 같은 mutex로 보호되는지 확인한다.
종료 경로 producer가 끝났을 때 consumer가 영원히 기다리지 않는지 확인한다.