Семафор идеально подходит для модели «производитель-потребитель», хотя у него есть и другие применения. Ваша логика программы отвечает за то, чтобы количество ожидаемых сообщений составлялось правильно. Если вы публикуете семафор, и никто еще не ждет его, тогда, когда они ждут, они сразу же продолжаются. Если ваша проблема такова, что ее можно объяснить с помощью значения счетчика семафора, то ее легко решить с помощью семафора.
Переменная условия в некоторых отношениях немного более прощающая. Например, вы можете использовать cond_broadcast, чтобы разбудить всех официантов, при этом производитель не знает, сколько их. И если вы cond_signal condvar, на котором никто не ждет, то ничего не произойдет. Это хорошо, если вы не знаете, будет ли заинтересованный слушатель. Именно поэтому слушатель должен всегда проверять состояние с мьютексом, удерживаемым перед ожиданием - если он этого не делает, он может пропустить сигнал и не просыпаться до следующего (что может быть никогда).
Таким образом, условная переменная подходит для уведомления заинтересованных сторон об изменении состояния: вы получаете мьютекс, изменяете состояние, сигнализируете (или транслируете) condvar и освобождаете мьютекс. Если это описывает вашу проблему, вы находитесь на территории Кондвар. Если разные слушатели интересуются разными состояниями, вы можете просто транслировать, и каждый из них по очереди проснется, выяснит, нашли ли они желаемое состояние, и если нет, то подождут снова.
Очень мрачно пытаться делать подобные вещи с мьютексом и семафором. Проблема возникает, когда вы хотите взять мьютекс, проверить состояние, а затем дождаться изменений на семафоре. Если вы не можете атомарно освободить мьютекс и ждать на семафоре (чего нельзя сделать в pthreads), вы в конечном итоге ждете семафор, удерживая мьютекс. Это блокирует мьютекс, а это означает, что другие не могут принять изменения, которые вас волнуют. Таким образом, у вас будет соблазн добавить еще один мьютекс, который зависит от ваших конкретных требований. И, может быть, еще один семафор. В результате получается неправильный код с опасными условиями гонки.
Переменные условия избегают этой проблемы, потому что вызов cond_wait автоматически освобождает мьютекс, освобождая его для использования другими. Мьютекс восстанавливается до возврата cond_wait.
IIRC можно реализовать своего рода condvar, используя только семафоры, но если мьютекс, который вы реализуете для работы с condvar, должен иметь trylock, то это серьезный головной убор, и время ожидания истекло. Не рекомендуется. Поэтому не думайте, что все, что вы можете сделать с condvar, может быть сделано с семафорами. Кроме того, у мьютексов может быть хорошее поведение, которого нет у семафоров, в основном избегание инверсии приоритетов.