Вызов pthread_cond_signal без блокировки мьютекса - PullRequest
77 голосов
/ 28 декабря 2010

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

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

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

Ответы [ 3 ]

133 голосов
/ 31 декабря 2010

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

Процесс 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(), но это может привести к менее оптимальному планированию потоков, и вы обязательно заблокировали мьютекс уже в этом коде путь из-за изменения самого условия).

46 голосов
/ 28 декабря 2010

Согласно этому руководству:

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

Значение оператора прогнозируемого поведения было объяснено Дэйвом Бутенхофом (автором Программирование с потоками POSIX ) на comp.programming.threads и доступно здесь .

4 голосов
/ 15 июня 2012

caf, в вашем примере кода процесс B изменяет condition без блокировки мьютекса.Если бы процесс B просто заблокировал мьютекс во время этой модификации, а затем все еще разблокировал мьютекс перед вызовом pthread_cond_signal, проблем не было бы - я прав в этом?* позиция правильная: вызов pthread_cond_signal без владения блокировкой мьютекса - плохая идея.Но пример Кафа на самом деле не является доказательством в поддержку этой позиции;это просто доказательство в поддержку гораздо более слабой (практически самоочевидной) позиции, что это плохая идея модифицировать общее состояние, защищенное мьютексом, если вы сначала не заблокировали этот мьютекс.в котором вызов pthread_cond_signal с последующим pthread_mutex_unlock возвращает правильное поведение, но вызов pthread_mutex_unlock с последующим pthread_cond_signal возвращает неправильное поведение?

...