C++ condition_variable

조건 변수 predicate

condition_variable의 핵심은 notify가 아니라 기다리는 조건이다. spurious wakeup이 가능하므로 wait는 반드시 predicate loop와 함께 쓰고, 상태 변경과 알림 순서를 분리해 읽는다.

01

공유 상태

큐가 비었는지, 작업이 끝났는지처럼 predicate가 되는 상태를 mutex로 보호한다.

조건은 데이터
02

wait 진입

unique_lock을 잡고 predicate 버전 wait를 사용해 깨어난 뒤 조건을 다시 검사한다.

while과 동일
03

상태 변경

생산자는 락 안에서 데이터를 넣거나 flag를 바꿔 predicate를 참으로 만든다.

순서 보장
04

notify

조건 변경 후 notify_one 또는 notify_all로 대기자를 깨운다.

알림은 힌트
notify_one
대기자 하나 깨움 큐 작업 하나처럼 한 스레드만 진행해도 충분할 때 사용한다.
경합 감소
notify_all
모든 대기자 깨움 종료 신호나 여러 조건 가능성이 있을 때 필요하다.
thundering herd
timeout
영원한 대기 방지 wait_for/wait_until은 시간 초과와 조건 만족을 구분해야 한다.
상태 재검사
lost wakeup
조건 없이 알림만 믿는 버그 wait 시작 전 notify가 지나가도 predicate가 남아 있으면 안전하다.
조건 저장

predicate wait · 락 종류 · 종료 조건 점검

predicate wait cv.wait(lock)만 쓰고 조건 재검사를 빠뜨리지 않았는지 확인한다.
락 종류 condition_variable은 unique_lock<mutex>가 필요함을 확인한다.
종료 대기 중인 스레드를 깨울 shutdown flag와 notify_all이 있는지 본다.

대기 기본형

std::unique_lock<std::mutex> lock(m);
cv.wait(lock, [&] { return !queue.empty() || done; });