Pthread_cond_wait против семафора

Каковы плюсы и минусы использования 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);
}

Каковы плюсы и минусы каждого метода?

Я только что понял, что «правильно инициализированный семафор» некорректно определен. Семафор установлен на 1 или на 0? Я бы сказал, что он должен быть установлен в 0. Тогда, защищает ли семафор cam-> status или нет?

Blaisorblade 02.06.2014 02:45

Во втором фрагменте, как упоминалось в других ответах, ваш поток будет заблокирован, пока мьютекс не освобожден. Таким образом, ваш метод sem_wait никогда не вернется, потому что никакой другой поток не может получить мьютекс и вызвать sem_signal. Однако я не буду, что делать, если я выпущу мьютекс до sem_wait и потребую его снова после ожидания. Я знаю, что эти шаги не атомарны, так что же произойдет?

sevenkplus 03.10.2016 18:31
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
48
2
29 824
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Во втором фрагменте вы получаете блокировку много раз, но никогда не снимаете ее.

В общем, состояние, в котором вы находитесь, может быть полностью выражено семафором, тогда вы можете использовать именно его. Структура блокировки меньше по размеру и требует меньше атомарных операций для проверки / установки / снятия.

В противном случае, если состояние сложное и разные части кода ожидают разных условий одной и той же переменной (например, здесь вы хотите x <10; там вы хотите y> x), используйте cond_wait.

Второй фрагмент правильный - пробуждение всегда вызывается сигналом семафора.

Blaisorblade 12.01.2009 12:04

@Blaisorblade, пробуждение правильное, проверка статуса - нет, потому что он не охраняется.

Alexis Wilke 28.05.2014 07:59

Это другая проблема, чем то, что описывает этот ответ - «во втором фрагменте вы получаете блокировку много раз, но никогда не снимаете ее». Я упоминал об этой проблеме в своем ответе выше (хотя и не очень конкретно). Но, снова взглянув на код, я понял, что на самом деле нельзя сказать, верен ли второй фрагмент или нет, потому что слишком много деталей отсутствует (см. Мой комментарий к вопросу). Но я сформулировал свой комментарий неправильно - я должен был сказать «проблемы, о которой вы говорите, нет, потому что ...».

Blaisorblade 02.06.2014 02:46

Условные выражения позволяют вам делать то, чего не могут делать семафоры.

Например, предположим, что у вас есть код, для которого требуется мьютекс m. Однако ему нужно дождаться, пока какой-то другой поток завершит свою задачу, поэтому он ждет семафор с именем s. Теперь любой поток, которому нужен m, заблокирован для запуска, даже если поток с m ожидает на s. Подобные ситуации можно разрешить с помощью условных выражений. Когда вы ожидаете выполнения условия, удерживаемый в данный момент мьютекс освобождается, поэтому другие потоки могут получить мьютекс. Итак, вернемся к нашему примеру и предположим, что условный c использовался вместо s. Теперь наш поток получает m, а затем условно ожидает на c. Это освобождает m, поэтому другие потоки могут продолжить. Когда c станет доступным, m будет восстановлен, и наш исходный поток сможет продолжить свой путь.

Условные переменные также позволяют вам разрешить потокам все, ожидающим условную переменную, продолжить работу через pthread_cond_broadcast. Кроме того, он также позволяет вам выполнять рассчитанное время ожидания, чтобы вам не пришлось ждать вечно.

Конечно, иногда вам не нужны условные переменные, поэтому в зависимости от ваших требований один или другой может быть лучше.

Это хороший ответ. Чтобы добавить к описанию, что делает условные выражения уникальными по сравнению с описанной комбинацией мьютекса и семафора, так это то, что условное выражение манипулирует парой мьютекс / семафор атомарно !!

Tall Jeff 23.09.2008 04:41
Ответ принят как подходящий

Семафор идеально подходит для модели производитель-потребитель, хотя имеет и другие применения. Логика вашей программы отвечает за обеспечение того, чтобы количество публикаций соответствовало количеству ожиданий. Если вы публикуете семафор, а его еще никто не ждет, то, когда они все же ждут, они немедленно продолжат. Если ваша проблема такова, что ее можно объяснить в терминах значения счетчика семафора, то ее легко решить с помощью семафора.

В некоторых отношениях условная переменная немного более снисходительна. Вы можете, например, использовать 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/

Фактически, во втором фрагменте семафор сам может защищать (или не защищать) флаг состояния (хотя я не могу представить себе хороший протокол блокировки для этого).

Blaisorblade 02.06.2014 02:48

Другие вопросы по теме