Когда мы должны использовать мьютекс, а когда - семафор?
Когда мы должны использовать мьютекс, а когда мы должны использовать семафор
Ответы (12)
Вот как я запоминаю, когда что использовать -
Семафор: используйте семафор, когда вы (поток) хотите заснуть, пока какой-либо другой поток не скажет вам проснуться. Семафор «вниз» происходит в одном потоке (производитель), а семафор «вверх» (для одного и того же семафора) происходит в другом потоке (потребителе), например: в проблеме производитель-потребитель производитель хочет спать, пока хотя бы один буферный слот не станет пустым - только потребительский поток может определить, когда слот буфера пуст.
Мьютекс: используйте мьютекс, когда вы (поток) хотите выполнить код, который не должен выполняться каким-либо другим потоком одновременно. Мьютекс «вниз» происходит в одном потоке, а «вверх» должен произойти в том же потоке позже. например: если вы удаляете узел из глобального связанного списка, вы не хотите, чтобы другой поток возился с указателями, пока вы удаляете узел. Когда вы получаете мьютекс и заняты удалением узла, если другой поток пытается получить тот же мьютекс, он будет переведен в спящий режим, пока вы не освободите мьютекс.
Spinlock: используйте спин-блокировку, когда вы действительно хотите использовать мьютекс, но вашему потоку не разрешено спать. например: обработчик прерывания в ядре ОС никогда не должен спать. Если это произойдет, система зависнет / выйдет из строя. Если вам нужно вставить узел в глобально общий связанный список из обработчика прерывания, получите спин-блокировку - вставьте узел - освободите спин-блокировку.
Мьютекс - это объект взаимного исключения, похожий на семафор, но разрешающий только один шкафчик за раз, и чьи ограничения владения могут быть более строгими, чем семафор.
Его можно рассматривать как эквивалент обычного подсчетного семафора (со счетчиком, равным единице) и требования, чтобы он мог быть освобожден только тем же потоком, который его заблокировал (a).
С другой стороны, семафор имеет произвольный счетчик и может быть заблокирован этим множеством шкафчиков одновременно. И у него может не быть требования, чтобы он был выпущен тем же потоком, который потребовал его (но, если нет, вы должны тщательно отслеживать, кто в настоящее время несет за это ответственность, как и выделенная память).
Итак, если у вас есть несколько экземпляров ресурса (скажем, три ленточных накопителя), вы можете использовать семафор со счетчиком 3. Обратите внимание, что это не говорит вам, какой из этих ленточных накопителей у вас есть, просто то, что у вас есть определенное количество.
Также с помощью семафоров один шкафчик может заблокировать несколько экземпляров ресурса, например, для копирования с ленты на ленту. Если у вас есть один ресурс (скажем, область памяти, которую вы не хотите повреждать), более подходит мьютекс.
Эквивалентные операции:
Counting semaphore Mutual exclusion semaphore
-------------------------- --------------------------
Claim/decrease (P) Lock
Release/increase (V) Unlock
В сторону: если вы когда-нибудь задумывались над причудливыми буквами, используемыми для запроса и выпуска семафоров, то это потому, что изобретатель был голландцем. Probeer te verlagen означает пытаться уменьшить, в то время как verhogen означает увеличивать.
(a) ... или его можно рассматривать как нечто совершенно отличное от семафора, что может быть безопаснее, учитывая их почти всегда разные способы использования.
mutex - это заявление, которое не дает мне руки, пока я не закончу; для ресурса, о существовании которого уже известно. И это будет продолжаться после того, как мьютекс будет выпущен. binary semaphore подходит, когда ресурс не существует, пока producer не предоставит его. После того, как consumer приходит и получает этот ресурс он исчезает навсегда (если / пока producer не создаст другой ресурс). Это разные концепции. Да, мьютекс или семафор можно использовать не по назначению. Но это было бы ошибкой.
- person ToolmakerSteve; 02.02.2017
Очень важно понимать, что мьютекс не семафор со счетчиком 1!
По этой причине существуют такие вещи, как двоичные семафоры (которые на самом деле являются семафорами со счетом 1).
Разница между мьютексом и двоичным семафором заключается в принципе владения:
Мьютекс захватывается задачей и, следовательно, также должен быть освобожден этой же задачей. Это позволяет исправить несколько проблем с бинарными семафорами (случайное освобождение, рекурсивная тупиковая ситуация и инверсия приоритета).
Предостережение: я написал «делает это возможным», если и как эти проблемы будут устранены, зависит от реализации ОС.
Поскольку мьютекс должен быть освобожден одной и той же задачей, это не очень хорошо для синхронизации задач. Но в сочетании с условными переменными вы получаете очень мощные строительные блоки для построения всех видов примитивов ipc.
Итак, моя рекомендация: если у вас есть чисто реализованные мьютексы и условные переменные (например, с потоками POSIX), используйте их.
Используйте семафоры только в том случае, если они точно соответствуют проблеме, которую вы пытаетесь решить, не пытайтесь создавать другие примитивы (например, rw-блокировки из семафоров, используйте для них мьютексы и условные переменные)
Есть много недопонимания мьютексов и семафоров. Лучшее объяснение, которое я нашел до сих пор, содержится в этой статье из трех частей:
Мьютекс против семафоров - Часть 1. Семафоры
Mutex vs. Семафоры - Часть 2: Мьютекс
Мьютекс против семафоров - Часть 3 (заключительная часть): Проблемы взаимного исключения
Хотя ответ @opaxdiablo совершенно правильный, я хотел бы отметить, что сценарий использования обоих вещей совершенно разный. Мьютекс используется для защиты частей кода от одновременного выполнения, семафоры используются для одного потока, чтобы сигнализировать о запуске другого потока.
/* Task 1 */
pthread_mutex_lock(mutex_thing);
// Safely use shared resource
pthread_mutex_unlock(mutex_thing);
/* Task 2 */
pthread_mutex_lock(mutex_thing);
// Safely use shared resource
pthread_mutex_unlock(mutex_thing); // unlock mutex
Сценарий семафора другой:
/* Task 1 - Producer */
sema_post(&sem); // Send the signal
/* Task 2 - Consumer */
sema_wait(&sem); // Wait for signal
Дополнительные пояснения см. На http://www.netrino.com/node/202.
sema_wait нет потоков :-) На мой взгляд, они оба относятся к ресурсам а уведомление, переданное другим потокам, является побочным эффектом (очень важным с точки зрения производительности) защиты.
- person paxdiablo; 28.10.2010
You say that the usage pattern of semaphores is to notify threads Одно замечание об уведомлении потоков. Вы можете безопасно вызвать sem_post из обработчика сигналов (pubs.opengroup.org/onlinepubs/ 009695399 / functions /), но не рекомендуется вызывать pthread_mutex_lock и pthread_mutex_unlock из обработчиков сигналов (manpages.ubuntu.com/manpages/lucid/man3/)
- person ; 05.03.2013
См. «Пример туалета» - http://pheatt.emporia.edu/courses/2010/cs557f10/hand07/Mutex%20vs_%20Semaphore.htm:
Мьютекс:
Ключ от туалета. Один человек может иметь ключ - занимать туалет - одновременно. Когда закончите, человек дает (освобождает) ключ следующему человеку в очереди.
Официально: «Мьютексы обычно используются для сериализации доступа к разделу реентерабельного кода, который не может выполняться одновременно более чем одним потоком. Объект мьютекса позволяет только одному потоку войти в контролируемый раздел, вынуждая другие потоки, которые пытаются получить доступ к этот раздел, чтобы дождаться, пока первый поток не выйдет из этого раздела ". Ссылка: Библиотека разработчика Symbian
(На самом деле мьютекс - это семафор со значением 1.)
Семафор:
Количество одинаковых бесплатных ключей от туалета. Например, у нас есть четыре туалета с одинаковыми замками и ключами. Счетчик семафоров - счетчик ключей - вначале установлен на 4 (все четыре туалета свободны), затем значение счетчика уменьшается по мере того, как люди входят. Если все туалеты заполнены, т.е. свободных ключей не осталось, счетчик семафоров равен 0. Теперь, когда eq. один человек выходит из туалета, семафор увеличивается до 1 (один свободный ключ) и передается следующему человеку в очереди.
Официально: «Семафор ограничивает количество одновременных пользователей общего ресурса до максимального числа. Потоки могут запрашивать доступ к ресурсу (уменьшая семафор) и могут сигнализировать, что они закончили использование ресурса (увеличивая семафор). " Ссылка: Библиотека разработчика Symbian
Пытаюсь не показаться глупым, но ничего не могу с собой поделать.
Ваш вопрос должен заключаться в том, в чем разница между мьютексом и семафором? А если быть более точным, следует задать вопрос: «Какая связь между мьютексом и семафором?»
(Я бы добавил этот вопрос, но я на сто процентов уверен, что какой-нибудь чрезмерно усердный модератор закроет его как дубликат, не понимая разницы между различием и отношением.)
В объектной терминологии мы можем заметить, что:
наблюдение.1 Семафор содержит мьютекс
наблюдение.2 Мьютекс не является семафором, а семафор не является мьютексом.
Есть некоторые семафоры, которые действуют как мьютекс, называемые двоичными семафорами, но они, черт возьми, НЕ мьютекс.
Существует специальный ингредиент, называемый Signaling (posix использует condition_variable для этого имени), необходимый для создания семафора из мьютекса. Думайте об этом как об источнике уведомлений. Если два или более потока подписаны на один и тот же источник уведомлений, то для пробуждения можно отправить им сообщение ОДНОМУ или ВСЕМ.
С семафорами могут быть связаны один или несколько счетчиков, которые охраняются мьютексом. Самый простой сценарий для семафора, есть единственный счетчик, который может быть либо 0, либо 1.
Вот где смятение вливается, как сезонный дождь.
Семафор со счетчиком, который может быть 0 или 1, НЕ является мьютексом.
Mutex имеет два состояния (0,1) и одно владение (задача). Семафор имеет мьютекс, несколько счетчиков и условную переменную.
Теперь используйте свое воображение, и каждая комбинация использования счетчика и времени подачи сигнала может создать один вид семафора.
Одиночный счетчик со значением 0 или 1 и сигнализация, когда значение переходит в 1 И затем разблокирует одного из парней, ожидающих сигнала == Двоичный семафор
Единый счетчик со значением от 0 до N и сигнализация, когда значение становится меньше N, и блокировка / ожидание, когда значение равно N == Семафор подсчета
Единый счетчик со значением от 0 до N и сигнализация, когда значение переходит в N, и блокирует / ожидает, когда значения меньше N == Семафор барьера (ну, если они не вызывают его, тогда они должны.)
Теперь к вашему вопросу, когда что использовать. (ИЛИ довольно правильный вопрос версии 3, когда использовать мьютекс, а когда использовать двоичный семафор, поскольку нет сравнения с небинарным семафором.) Используйте мьютекс, когда 1. вам нужно настраиваемое поведение, которое не обеспечивается двоичным семафор, например, спин-блокировка, быстрая блокировка или рекурсивная блокировка. Обычно мьютексы можно настраивать с помощью атрибутов, но настройка семафора - это не что иное, как написание нового семафора. 2. вам нужен легкий ИЛИ более быстрый примитив
Используйте семафоры, когда они точно предоставляют то, что вы хотите.
Если вы не понимаете, что предоставляется вашей реализацией двоичного семафора, то, IMHO, используйте мьютекс.
И, наконец, прочтите книгу, а не полагайтесь только на ТАК.
Я думаю, что вопрос должен заключаться в разнице между мьютексом и двоичным семафором.
Mutex = Это механизм блокировки владения, только поток, получивший блокировку, может снять блокировку.
двоичный семафор = это скорее сигнальный механизм, любой другой поток с более высоким приоритетом, если он хочет, может сигнализировать и брать блокировку.
Мьютекс предназначен для защиты общего ресурса.
Семафор предназначен для распределения потоков.
Mutex:
Представьте, что есть билеты на продажу. Мы можем смоделировать случай, когда многие люди покупают билеты одновременно: каждый человек является цепочкой для покупки билетов. Очевидно, нам нужно использовать мьютекс для защиты билетов, потому что это общий ресурс.
Семафор:
Представьте, что нам нужно произвести вычисление, как показано ниже:
c = a + b;
Кроме того, нам нужна функция geta() для вычисления a, функция getb() для вычисления b и функция getc() для вычисления c = a + b.
Очевидно, что мы не сможем выполнить c = a + b, если geta() и getb() не будут завершены.
Если три функции являются тремя потоками, нам нужно распределить три потока.
int a, b, c;
void geta()
{
a = calculatea();
semaphore_increase();
}
void getb()
{
b = calculateb();
semaphore_increase();
}
void getc()
{
semaphore_decrease();
semaphore_decrease();
c = a + b;
}
t1 = thread_create(geta);
t2 = thread_create(getb);
t3 = thread_create(getc);
thread_join(t3);
С помощью семафора приведенный выше код может гарантировать, что t3 не будет выполнять свою работу, пока t1 и t2 не выполнят свою работу.
Одним словом, семафор должен заставить потоки выполняться в логическом порядке, тогда как мьютекс должен защищать совместно используемый ресурс.
Таким образом, это НЕ одно и то же, даже если некоторые люди всегда говорят, что мьютекс - это специальный семафор с начальным значением 1. Вы можете сказать и так, но обратите внимание, что они используются в разных случаях. Не заменяйте одно другим, даже если вы можете это сделать.
x = getx(); y = gety(); z = x + y; По какой-то причине мы используем три потока для выполнения трех задач, теперь порядок потоков очень важен, потому что мы не можем сделать x + y, пока getx и gety не завершены. Одним словом, семафор используется, когда мы заботимся о порядке выполнения многопоточности.
- person Yves; 16.08.2017
x и y, затем вычислите z = x + y. Я знаю, что в java есть CyclicBarrier. Кроме того, я не уверен, что могу сказать, что mapreduce также используется для семафоров, потому что я не могу reduce, пока не будут завершены все map.
- person prayagupd; 16.08.2017
Как уже указывалось, семафор со счетчиком, равным единице, - это то же самое, что и «двоичный» семафор, который является тем же самым, что и мьютекс.
Основное, что я видел семафоры со счетчиком больше одного, - это ситуации производителя / потребителя, в которых у вас есть очередь определенного фиксированного размера.
Значит, у вас есть два семафора. Первый семафор изначально установлен как количество элементов в очереди, а второй семафор установлен на 0. Производитель выполняет операцию P над первым семафором, добавляет в очередь. и выполняет операцию V на втором. Потребитель выполняет операцию P со вторым семафором, удаляет его из очереди, а затем выполняет операцию V над первым.
Таким образом, производитель блокируется всякий раз, когда он заполняет очередь, а потребитель блокируется, когда очередь пуста.
Все приведенные выше ответы хорошего качества, но этот - просто для запоминания. Название Мьютекс происходит от слова взаимоисключающий, поэтому у вас есть мотивация думайте о блокировке мьютекса как о взаимном исключении между двумя, как о только по одному за раз, и если я обладал им, вы можете получить его только после того, как я его отпущу. С другой стороны, такой случай не существует для Семафор strong> похож на сигнал светофора (что также означает слово «семафор»).
Мьютекс - это особый случай семафора. Семафор позволяет нескольким потокам войти в критическую секцию. При создании семафора вы определяете, как могут быть разрешены потоки в критической секции. Конечно, ваш код должен уметь обрабатывать несколько обращений к этому критическому разделу.
Бинарный семафор и мьютекс разные. С точки зрения ОС двоичный семафор и счетный семафор реализованы одинаково, и двоичный семафор может иметь значение 0 или 1.
Mutex -> Может использоваться только для одной-единственной цели взаимного исключения для критического участка кода.
Семафор -> Может использоваться для решения множества задач. Двоичный семафор может использоваться для сигнализации, а также для решения проблемы взаимного исключения. При инициализации 0 он решает проблему сигнализации, а при инициализации 1 решает проблему взаимного исключения.
Когда количество ресурсов больше и их необходимо синхронизировать, мы можем использовать семафор подсчета.
В своем блоге я подробно рассмотрел эти темы.
https://designpatterns-oo-cplusplus.blogspot.com/2015/07/synchronization-primitives-mutex-and.html