2010-12-28 3 views
68

Я где-то читал, что мы должны зафиксировать семафор перед вызовом pthread_cond_signal и разблокировать mutext после его вызова:Вызов pthread_cond_signal без блокировки мьютекса

Процедура pthread_cond_signal() является используется для сигнализации (или проснуться) другой нить, которая ждет на условие переменной. Он должен быть , вызываемый после блокировки мьютекса, и должен разблокировать мьютексы для Процедура pthread_cond_wait() для завершена.

Мой вопрос: не это OK для вызова pthread_cond_signal или pthread_cond_broadcast методов без блокировки мьютекса?

ответ

116

Если вы не блокируете мьютекс в кодексе, который изменяет состояние и сигналы, вы можете потерять пробуждения. Рассмотрю эту пару процессов:

Процесса 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, но процесс А задерживается в ожидании переменной состояния - он пропустил сигнал пробуждения.Если мы изменяем процесс В, чтобы заблокировать мьютекс:

Процесс B (правильный):

pthread_mutex_lock(&mutex); 
condition = TRUE; 
pthread_cond_signal(&cond); 
pthread_mutex_unlock(&mutex); 

... то выше, может не произойти; пробуждение никогда не будет пропущено.

(Обратите внимание, что вы можете фактически переместить сам pthread_cond_signal() после pthread_mutex_unlock(), но это может привести к снижению оптимального планирования потоков, и вы обязательно заперта мьютекс уже в этом коде пути из-за изменения самого состояния).

+1

имеет смысл! спасибо :) – Meysam

+2

@Nemo: Да, на «правильном» пути «pthread_signal_cond()' * can * может быть перемещен после разблокировки мьютекса, хотя, вероятно, лучше не делать этого. Возможно, правильнее сказать, что в тот момент, когда вы вызываете 'pthread_signal_cond()', вам уже необходимо заблокировать мьютекс, чтобы изменить само условие. – caf

+0

@Nemo: Да, код сломан, поэтому он помечен как «неправильный» - мой опыт заключается в том, что люди, которые задают этот вопрос, часто рассматривают возможность полного блокирования на сигнальном пути. Возможно, ваш опыт отличается. – caf

43

Согласно этой инструкции:

В pthread_cond_broadcast() или pthread_cond_signal() функции можно назвать нить или нет в данный момент владеет мьютексом что нити, требующая pthread_cond_wait() или pthread_cond_timedwait() имеет , связанные с переменная состояния во время их ожидания; Однако, если предсказуемого поведения планирования требуется , то, что мьютекс должен быть заблокирован в потоке вызывающего pthread_cond_broadcast() или pthread_cond_signal().

Смысл предсказуемы планирования поведения заявление было объяснено Dave Butenhof (автор Programming with POSIX Threads) на comp.programming.threads и доступен here.

+4

+1 для связи почты с Dave Butenhof. Я всегда задавался вопросом об этой проблеме, теперь я знаю ... Узнал что-то важное сегодня. Благодарю. –

+0

Если требуется предсказуемое поведение при планировании, тогда поместите операторы в один поток в том порядке, в котором вы хотите, или используете приоритеты потоков. – Kaz

4

caf, в вашем примере кода, процесс B изменяет condition без блокировки мьютексов. Если Process B просто заблокировал мьютекс во время этой модификации, а затем все еще разблокировал мьютекс перед вызовом pthread_cond_signal, не было бы проблем - я прав об этом?

Я верю, что информация о в кафе верна: вызов pthread_cond_signal без владения блокировкой мьютекса - это плохая идея. Но пример caf's фактически не является доказательством в поддержку этой позиции; это просто доказательство в поддержку гораздо более слабой (практически очевидной) позиции, что Bad Idea модифицирует разделяемое состояние, защищенное мьютексом, если вы не заблокировали этот мьютекс в первую очередь.

Кто может предоставить некоторые примеры кода, в котором призвании pthread_cond_signal следуют pthread_mutex_unlock урожаи правильное поведение, но вызывая pthread_mutex_unlock с последующим pthread_cond_signal выходами неправильное поведение?

+0

Уведомление @caf – Meysam

+2

На самом деле, я думаю, что мой вопрос является дубликатом [этого] (http://stackoverflow.com/questions/6419117/signal-and-unlock-order), и ответ: «Все в порядке, вы может * полностью * вызывать pthread_cond_signal, не имея блокировки мьютекса. Нет проблемы с корректностью. Но в общих реализациях вы пропустите умную оптимизацию внутри pthreads, поэтому немного предпочтительнее вызвать pthread_cond_signal, сохраняя при этом блокировку.« – Quuxplusone

+0

Я сделал это замечание в последнем абзаце своего ответа. – caf