pthread_cond_wait и требование мьютекса - PullRequest
17 голосов
/ 11 июня 2011

Почему необходимо заблокировать мьютекс перед вызовом pthread_cond_wait?

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

спасибо за вашу помощь.

Ответы [ 3 ]

26 голосов
/ 11 июня 2011

Почему необходимо заблокировать мьютекс перед вызовом pthread_cond_wait?

Потому что в противном случае есть неизбежное состояние гонки.

Мьютекс защищает общее состояние. Переменная условия связана с некоторым предикатом («условием») состояния. Основная идея заключается в том, что вы хотите:

1) проверить предикат

2) если предикат ложен, ложитесь спать, пока он не станет истинным

В параллельной системе некоторый поток всегда может сделать предикат истинным между (1) и (2). Чтобы избежать этой гонки, вы должны удерживать мьютекс перед (1), и вы должны разблокировать его атомарно, как вы выполняете (2).

Например, для очереди предикатом может быть «очередь не пуста». Но между временем, когда вы проверяете, не является ли очередь непустой, и временем, когда вы засыпаете, какой-то другой поток может что-то добавить в очередь.

Таким образом, вы должны удерживать мьютекс как при проверке предиката, так и во время вызова pthread_cond_wait.

Кроме того, обязательно ли брать блокировку (на том же мьютексе) перед вызовом pthread_cond_signal?

Насколько мне известно, в этом нет фундаментальной проблемы; это только вводит потенциальную неэффективность.

Здесь опять-таки, какое бы разделяемое состояние вы ни изменяли (и, следовательно, делали предикат истинным), оно должно быть защищено мьютексом. Поэтому каждый раз, когда вы хотите сообщить о состоянии, вы все равно должны удерживать мьютекс.

Если вы освобождаете мьютекс перед тем, как сообщить об этом условии, предикат может стать ложным между действиями из-за действия какого-то другого потока. Эта гонка не вызывает сбоев, потому что любой поток, ожидающий условия, должен в любом случае дважды проверить предикат, прежде чем продолжить ... Но зачем ставить его из-за проблемы?

Итог: просто следуйте инструкциям, и вам даже не нужно думать об этих вопросах. : -)

1 голос
/ 11 июня 2011

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

В отличие от мониторов Java, pthread_cond_{signal,broadcast}() не должен содержать мьютекс. Сигнализация переменной условия, когда ни один поток не ожидает этой условной переменной, теряется, но это не должно иметь большого значения, поскольку сигнал также может быть потерян, если производитель начнет работать раньше потребителя.

1 голос
/ 11 июня 2011

Переменные условия предназначены для синхронизации с условием, которое вы ожидаете изменить. Блокировка гарантирует, что:

  • Изменение можно надежно наблюдать в ожидающих потоках
  • Изменяемый элемент каким-то образом не изменяется другим потоком, в то время как один из проснувшихся потоков наблюдает его

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

...