Подтвердить что ты не робот

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);
}

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

4b9b3361

Ответ 1

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

В некоторых отношениях переменная состояния немного более прощающая. Вы можете, например, использовать cond_broadcast для пробуждения всех официантов, без того, чтобы продюсер знал, сколько их там. И если вы cond_signal condvar, никто не ждет на нем, тогда ничего не происходит. Это хорошо, если вы не знаете, будет ли интерес слушателем. Кроме того, слушатель должен всегда проверять состояние с помощью мьютекса, находящегося перед ожиданием, - если они этого не делают, тогда они могут пропустить сигнал и не просыпаться до следующего (что никогда не будет).

Итак, переменная условия подходит для уведомления заинтересованных сторон о том, что состояние изменилось: вы приобретаете мьютекс, изменяете состояние, сигнализируете (или транслируете) condvar и освобождаете мьютекс. Если это описывает вашу проблему, вы находитесь на территории condvar. Если разные слушатели заинтересованы в разных состояниях, вы можете просто транслировать, и каждый из них, в свою очередь, проснется, выяснит, нашли ли они состояние, которое они хотят, и если не ждать снова.

Очень грубо на самом деле пытаться подобным образом использовать мьютекс и семафор. Проблема возникает, когда вы хотите принять мьютекс, проверить состояние, а затем ждать семафора для изменений. Если вы не можете атомизировать мьютекс и ждать на семафоре (который в pthreads вы не можете), вы в конечном итоге ожидаете семафора, удерживая мьютекс. Это блокирует мьютекс, а это означает, что другие не могут принять его, чтобы внести изменения, о которых вы заботитесь. Таким образом, у вас возникнет соблазн добавить еще один мьютекс таким образом, который зависит от ваших конкретных требований. И, возможно, другой семафор. Результат, как правило, неправильный код с вредными условиями гонки.

Переменные условия выходят из этой проблемы, так как вызов cond_wait автоматически освобождает мьютекс, освобождая его для использования другими. Мьютекс восстанавливается до возврата cond_wait.

IIRC можно реализовать какой-то condvar, используя только семафоры, но если у мьютекса, который вы реализуете, чтобы пойти с condvar, требуется иметь trylock, то это серьезный головорезчик, а ожидания по таймеру отсутствуют. Не рекомендуется. Поэтому не предполагайте, что все, что вы можете сделать с condvar, можно сделать с помощью семафоров. Плюс, конечно, мьютексы могут иметь приятное поведение, которое не имеет семафоров, в первую очередь избегание приоритетов.

Ответ 2

Условные слова позволяют делать некоторые вещи, которые не имеют семафоров.

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

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

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

Ответ 3

Второй фрагмент яркий, не делайте этого.

В других ответах есть хорошее обсуждение относительных достоинств; Я просто добавлю, что pthread_cond_broadcast является явным преимуществом переменных условия.

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

В самом деле, во втором фрагменте у вас нет блокировки, защищающей чтение статуса cam- > , поэтому он доступен через гонку данных. Большинство платформ позволят вам уйти от этого в этом конкретном примере, но это имеет undefined семантику, POSIX и модель памяти следующих стандартов C/С++.

Фактически, реальное состояние гонки возможно, если другой поток распределяет новую структуру кулачка и перезаписывает кулачок; ожидающий поток может видеть обновление указателя "cam", не видя инициализации статуса cam- > . Действительно, второй фрагмент задает проблемы, в данном случае и в целом.

http://www.hpl.hp.com/personal/Hans_Boehm/c++mm/

Ответ 4

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

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

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