Вызов pthread_cond_signal без блокировки мьютекса
Я где-то читал, что мы должны заблокировать мьютекс перед вызовом pthread_cond_signal и разблокировать мьютекст после его вызова:
Подпрограмма pthread_cond_signal() используется для сигнализации (или пробуждения) другого поток, который ожидает переменная условия. Должен быть вызываемый после мьютекса, заблокирован и должен разблокировать мьютекс, чтобы pthread_cond_wait() для полная.
Мой вопрос: не в порядке ли вызывать методы pthread_cond_signal или pthread_cond_broadcast без блокировки мьютекса?
Ответы
Ответ 1
Если вы не блокируете мьютекс в кодексе, который изменяет состояние и сигналы, вы можете потерять пробуждения. Рассмотрим эту пару процессов:
Процесс A:
pthread_mutex_lock(&mutex);
while (condition == FALSE)
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
Процесс B (неверный):
condition = TRUE;
pthread_cond_signal(&cond);
Затем рассмотрим это возможное чередование инструкций, где condition
начинается как FALSE
:
Process A Process B
pthread_mutex_lock(&mutex);
while (condition == FALSE)
condition = TRUE;
pthread_cond_signal(&cond);
pthread_cond_wait(&cond, &mutex);
condition
теперь TRUE
, но процесс A застрял в ожидании от переменной условия - он пропустил сигнал пробуждения. Если мы изменим процесс B для блокировки мьютекса:
Процесс B (правильный):
pthread_mutex_lock(&mutex);
condition = TRUE;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
... то вышеуказанное не может произойти; пробуждение никогда не будет пропущено.
(Обратите внимание, что вы действительно можете переместить pthread_cond_signal()
непосредственно после pthread_mutex_unlock()
, но это может привести к менее оптимальному планированию потоков, и вы обязательно заблокировали мьютекс уже на этом пути кода из-за изменения условия сам по себе).
Ответ 2
В соответствии с этим руководством:
pthread_cond_broadcast()
или pthread_cond_signal()
функции может быть вызван потоком, независимо от того, владеет ли он в настоящее время мьютексом, который потоки, вызывающие pthread_cond_wait()
или pthread_cond_timedwait()
имеют связанный с переменной условия во время их ожидания; однако, если предсказуемое поведение планирования требуется, то мьютекс должен быть заблокирован вызовом потока pthread_cond_broadcast()
или pthread_cond_signal()
.
Значение предсказуемого описания поведения планирования объяснялось Дэйвом Бутенхофом (автором Программирование с потоками POSIX) на comp.programming.threads и доступен здесь.
Ответ 3
caf, в вашем примере кода Process B изменяет condition
без блокировки мьютекса в первую очередь. Если Process B просто заблокировал мьютекс во время этой модификации, а затем все еще разблокировал мьютекс перед вызовом pthread_cond_signal
, не было бы проблем --- я прав об этом?
Я уверен, что позиция в кафе правильная: вызов pthread_cond_signal
без владения блокировкой мьютекса - это плохая идея. Но пример кафе фактически не является доказательством в поддержку этой позиции; это просто свидетельствует в пользу гораздо более слабого (практически очевидного) положения о том, что Bad Idea модифицирует разделяемое состояние, защищенное мьютексом, если вы не заблокировали этот мьютекс в первую очередь.
Может ли кто-нибудь предоставить некоторый пример кода, в котором вызов pthread_cond_signal
, за которым следует pthread_mutex_unlock
, дает правильное поведение, но вызов pthread_mutex_unlock
, за которым следует pthread_cond_signal
, приводит к некорректному поведению?