Каковы плюсы и минусы использования pthread_cond_wait или семафора?
Жду такого изменения состояния:
pthread_mutex_lock(&cam->video_lock);
while(cam->status == WAIT_DISPLAY) {
pthread_cond_wait(&cam->video_cond, &cam->video_lock);
}
pthread_mutex_unlock(&cam->video_lock);
Используя правильно инициализированный семафор, я думаю, что смогу сделать это так:
while(cam->status == WAIT_DISPLAY) {
sem_wait(&some_semaphore);
}
Каковы плюсы и минусы каждого метода?
Во втором фрагменте, как упоминалось в других ответах, ваш поток будет заблокирован, пока мьютекс не освобожден. Таким образом, ваш метод sem_wait никогда не вернется, потому что никакой другой поток не может получить мьютекс и вызвать sem_signal. Однако я не буду, что делать, если я выпущу мьютекс до sem_wait и потребую его снова после ожидания. Я знаю, что эти шаги не атомарны, так что же произойдет?





Во втором фрагменте вы получаете блокировку много раз, но никогда не снимаете ее.
В общем, состояние, в котором вы находитесь, может быть полностью выражено семафором, тогда вы можете использовать именно его. Структура блокировки меньше по размеру и требует меньше атомарных операций для проверки / установки / снятия.
В противном случае, если состояние сложное и разные части кода ожидают разных условий одной и той же переменной (например, здесь вы хотите x <10; там вы хотите y> x), используйте cond_wait.
Второй фрагмент правильный - пробуждение всегда вызывается сигналом семафора.
@Blaisorblade, пробуждение правильное, проверка статуса - нет, потому что он не охраняется.
Это другая проблема, чем то, что описывает этот ответ - «во втором фрагменте вы получаете блокировку много раз, но никогда не снимаете ее». Я упоминал об этой проблеме в своем ответе выше (хотя и не очень конкретно). Но, снова взглянув на код, я понял, что на самом деле нельзя сказать, верен ли второй фрагмент или нет, потому что слишком много деталей отсутствует (см. Мой комментарий к вопросу). Но я сформулировал свой комментарий неправильно - я должен был сказать «проблемы, о которой вы говорите, нет, потому что ...».
Условные выражения позволяют вам делать то, чего не могут делать семафоры.
Например, предположим, что у вас есть код, для которого требуется мьютекс m. Однако ему нужно дождаться, пока какой-то другой поток завершит свою задачу, поэтому он ждет семафор с именем s. Теперь любой поток, которому нужен m, заблокирован для запуска, даже если поток с m ожидает на s. Подобные ситуации можно разрешить с помощью условных выражений. Когда вы ожидаете выполнения условия, удерживаемый в данный момент мьютекс освобождается, поэтому другие потоки могут получить мьютекс. Итак, вернемся к нашему примеру и предположим, что условный c использовался вместо s. Теперь наш поток получает m, а затем условно ожидает на c. Это освобождает m, поэтому другие потоки могут продолжить. Когда c станет доступным, m будет восстановлен, и наш исходный поток сможет продолжить свой путь.
Условные переменные также позволяют вам разрешить потокам все, ожидающим условную переменную, продолжить работу через pthread_cond_broadcast. Кроме того, он также позволяет вам выполнять рассчитанное время ожидания, чтобы вам не пришлось ждать вечно.
Конечно, иногда вам не нужны условные переменные, поэтому в зависимости от ваших требований один или другой может быть лучше.
Это хороший ответ. Чтобы добавить к описанию, что делает условные выражения уникальными по сравнению с описанной комбинацией мьютекса и семафора, так это то, что условное выражение манипулирует парой мьютекс / семафор атомарно !!
Семафор идеально подходит для модели производитель-потребитель, хотя имеет и другие применения. Логика вашей программы отвечает за обеспечение того, чтобы количество публикаций соответствовало количеству ожиданий. Если вы публикуете семафор, а его еще никто не ждет, то, когда они все же ждут, они немедленно продолжат. Если ваша проблема такова, что ее можно объяснить в терминах значения счетчика семафора, то ее легко решить с помощью семафора.
В некоторых отношениях условная переменная немного более снисходительна. Вы можете, например, использовать cond_broadcast, чтобы разбудить всех официантов, не зная, сколько их осталось. И если вы cond_signal condvar, и никто его не ждет, то ничего не произойдет. Это хорошо, если вы не знаете, заинтересуется ли слушатель. Вот почему слушатель всегда должен проверять состояние с удерживаемым мьютексом перед ожиданием - если они этого не сделают, они могут пропустить сигнал и не проснуться до следующего (что могло быть никогда).
Таким образом, переменная условия подходит для уведомления заинтересованных сторон об изменении состояния: вы получаете мьютекс, изменяете состояние, сигнализируете (или передаете) условную переменную и освобождаете мьютекс. Если это описывает вашу проблему, вы находитесь на территории кондваров. Если разные слушатели заинтересованы в разных состояниях, вы можете просто транслировать, и каждый по очереди проснется, выяснит, нашли ли они желаемое состояние, а если нет, подождите снова.
Действительно, очень сложно пытаться делать такие вещи с мьютексом и семафором. Проблема возникает, когда вы хотите взять мьютекс, проверить какое-то состояние, а затем дождаться изменений семафора. Если вы не можете атомарно освободить мьютекс и дождаться семафора (что в pthreads вы не можете), вы в конечном итоге будете ждать семафор, удерживая мьютекс. Это блокирует мьютекс, а это означает, что другие не могут воспользоваться им, чтобы внести нужное вам изменение. Таким образом, у вас возникнет соблазн добавить еще один мьютекс в зависимости от ваших конкретных требований. И, может быть, еще один семафор. В результате обычно получается некорректный код с опасными условиями гонки.
Переменные условия позволяют избежать этой проблемы, потому что вызов cond_wait автоматически освобождает мьютекс, освобождая его для использования другими. Мьютекс восстанавливается до возврата cond_wait.
IIRC можно реализовать своего рода condvar, используя только семафоры, но если мьютекс, который вы реализуете для работы с condvar, должен иметь trylock, то это серьезная проблема, и время ожидания истекло. Не рекомендуется. Так что не думайте, что все, что вы можете сделать с condvar, можно сделать с помощью семафоров. Плюс, конечно, мьютексы могут иметь приятное поведение, которого нет у семафоров, в основном предотвращение инверсии приоритета.
Второй фрагмент колоритный, не делайте этого.
В других ответах есть хорошее обсуждение относительных достоинств; Я просто добавлю, что pthread_cond_broadcast - явное преимущество условных переменных.
Кроме того, я просто больше привык к условным переменным для этого, поскольку они используются в Java, даже потому, что они помогают избежать гонок при проверке общих флагов.
Действительно, во втором фрагменте у вас нет блокировки, защищающей чтение cam-> status, поэтому доступ к нему осуществляется через гонку данных. Большинство платформ позволят вам обойтись без этого в этом конкретном примере, но он имеет неопределенную семантику в соответствии с POSIX и моделью памяти следующих стандартов C / C++.
Фактически, настоящая гонка возможна, если другой поток выделяет новую структуру кулачка и перезаписывает кулачок; ожидающий поток может увидеть обновление указателя 'cam', не увидев инициализацию cam-> status. Действительно, второй фрагмент вызывает проблемы в данном случае и в целом.
http://www.hpl.hp.com/personal/Hans_Boehm/c++mm/
Фактически, во втором фрагменте семафор сам может защищать (или не защищать) флаг состояния (хотя я не могу представить себе хороший протокол блокировки для этого).
Я только что понял, что «правильно инициализированный семафор» некорректно определен. Семафор установлен на 1 или на 0? Я бы сказал, что он должен быть установлен в 0. Тогда, защищает ли семафор cam-> status или нет?