# Monitor A **monitor** bundles a [[sync-mutex|mutex]] together with one or more **condition variables**, giving threads a structured way to wait for a condition to become true while holding the lock that protects it. The concept was formalized by C.A.R. Hoare and Per Brinch Hansen in the 1970s; in most languages today it isn't a separate keyword but a pattern built from a mutex plus `pthread_cond_t` (POSIX) or `std::condition_variable` (C++). ```c #include pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t not_empty = PTHREAD_COND_INITIALIZER; int queue_size = 0; void consume(void) { pthread_mutex_lock(&mutex); while (queue_size == 0) { pthread_cond_wait(¬_empty, &mutex); // atomically unlocks + sleeps } queue_size--; pthread_mutex_unlock(&mutex); } void produce(void) { pthread_mutex_lock(&mutex); queue_size++; pthread_cond_signal(¬_empty); pthread_mutex_unlock(&mutex); } ``` ## Why `wait` needs the mutex `pthread_cond_wait` takes the mutex as an argument because it has to unlock it and put the thread to sleep as a single atomic step. If those were two separate calls, a `signal` from another thread could slip in during the gap between unlocking and actually going to sleep, and the wakeup would be lost forever. This is the classic **lost wakeup** bug, and it's the entire reason condition variables are always paired with the mutex that protects the condition they represent, rather than being a standalone primitive. ## Why the condition is checked in a loop, not an `if` `pthread_cond_wait` can return even when no one called `signal` (a **spurious wakeup**, permitted by POSIX to simplify certain implementations), and even a genuine `signal` only guarantees the condition was true at the moment it was sent, not at the moment this thread actually wakes up and reacquires the mutex. Some other thread may have grabbed the resource first. Re-checking the condition in a `while` loop after waking up, rather than assuming it's now safe, is what makes the pattern correct in both cases.