Когда мы должны использовать мьютекс, а когда - семафор?
Когда мы должны использовать мьютекс, а когда - семафор?
Ответы:
Вот как я запоминаю, когда что использовать -
Семафор: используйте семафор, когда вы (поток) хотите заснуть, пока какой-либо другой поток не скажет вам проснуться. Семафор «вниз» происходит в одном потоке (производитель), а семафор «вверх» (для одного и того же семафора) происходит в другом потоке (потребителе), например: в проблеме производитель-потребитель производитель хочет спать, пока хотя бы один буферный слот не станет пустым - только потребительский поток может определить, когда слот буфера пуст.
Мьютекс: используйте мьютекс, когда вы (поток) хотите выполнить код, который не должен выполняться каким-либо другим потоком одновременно. Мьютекс «вниз» происходит в одном потоке, а «вверх» должен происходить в том же потоке позже. например: если вы удаляете узел из глобального связанного списка, вы не хотите, чтобы другой поток возился с указателями, пока вы удаляете узел. Когда вы получаете мьютекс и заняты удалением узла, если другой поток пытается получить тот же мьютекс, он будет переведен в спящий режим, пока вы не освободите мьютекс.
Spinlock: используйте спин-блокировку, если вы действительно хотите использовать мьютекс, но вашему потоку не разрешено спать. например: обработчик прерывания в ядре ОС никогда не должен спать. Если это произойдет, система зависнет / выйдет из строя. Если вам нужно вставить узел в глобально общий связанный список из обработчика прерывания, приобретите спин-блокировку - вставьте узел - освободите спин-блокировку.
Мьютекс - это объект взаимного исключения, похожий на семафор, но разрешающий только один шкафчик за раз, и чьи ограничения владения могут быть более строгими, чем семафор.
Его можно рассматривать как эквивалент обычного семафора подсчета (со счетом один) и требования, чтобы он мог быть освобожден только тем же потоком, который его заблокировал (a) .
С другой стороны, семафор имеет произвольный счетчик и может быть заблокирован этим множеством шкафчиков одновременно. И у него может не быть требования, чтобы он был выпущен тем же потоком, который потребовал его (но, если нет, вы должны тщательно отслеживать, кто в настоящее время несет за это ответственность, как и выделенная память).
Итак, если у вас есть несколько экземпляров ресурса (скажем, три ленточных накопителя), вы можете использовать семафор со счетчиком 3. Обратите внимание, что это не говорит вам, какой из этих ленточных накопителей у вас есть, просто то, что у вас есть определенное количество.
Также с помощью семафоров один шкафчик может заблокировать несколько экземпляров ресурса, например, для копирования с ленты на ленту. Если у вас есть один ресурс (скажем, область памяти, которую вы не хотите повреждать), мьютекс более подходит.
Эквивалентные операции:
Counting semaphore Mutual exclusion semaphore
-------------------------- --------------------------
Claim/decrease (P) Lock
Release/increase (V) Unlock
Кроме того: если вы когда-нибудь задумывались над причудливыми буквами, используемыми для запроса и выпуска семафоров, то это потому, что изобретатель был голландцем. Probeer te verlagen означает пытаться уменьшить, а verhogen - увеличить.
(а) ... или его можно рассматривать как нечто совершенно отличное от семафора, что может быть безопаснее, учитывая их почти всегда разные способы использования.
Очень важно понимать, что мьютекс - это не семафор со счетом 1!
По этой причине существуют такие вещи, как двоичные семафоры (которые на самом деле являются семафорами со счетом 1).
Разница между мьютексом и двоичным семафором заключается в принципе владения:
Мьютекс приобретается задачей и, следовательно, также должен быть освобожден этой же задачей. Это позволяет исправить несколько проблем с бинарными семафорами (случайное освобождение, рекурсивная тупиковая ситуация и инверсия приоритета).
Предостережение: я написал «делает это возможным», если и как эти проблемы будут устранены, зависит от реализации ОС.
Поскольку мьютекс должен быть освобожден одной и той же задачей, это не очень хорошо для синхронизации задач. Но в сочетании с условными переменными вы получите очень мощные строительные блоки для построения всех видов примитивов ipc.
Поэтому я рекомендую: если у вас есть чисто реализованные мьютексы и условные переменные (например, с потоками POSIX), используйте их.
Используйте семафоры, только если они точно подходят для задачи, которую вы пытаетесь решить, не пытайтесь создавать другие примитивы (например, rw-блокировки из семафоров, используйте для них мьютексы и условные переменные)
Есть много недопонимания мьютексов и семафоров. Лучшее объяснение, которое я нашел до сих пор, содержится в этой статье из трех частей:
Мьютекс против семафоров - Часть 1: семафоры
Мьютекс против семафоров - Часть 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
:-) На мой взгляд, они оба относятся к ресурсам, а уведомление, передаваемое другим потокам, является побочным эффектом (очень важным с точки зрения производительности) защита.
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/… )
См. «Пример туалета» - http://pheatt.emporia.edu/courses/2010/cs557f10/hand07/Mutex%20vs_%20Semaphore.htm :
Мьютекс:
Это ключ от туалета. Один человек может иметь ключ - занимать туалет - одновременно. По окончании человек дает (освобождает) ключ следующему человеку в очереди.
Официально: «Мьютексы обычно используются для сериализации доступа к разделу реентерабельного кода, который не может выполняться одновременно более чем одним потоком. Объект мьютекса позволяет только одному потоку войти в контролируемый раздел, вынуждая другие потоки, которые пытаются получить доступ к этот раздел, чтобы ждать, пока первый поток не выйдет из этого раздела ". Ссылка: Библиотека разработчика Symbian
(На самом деле мьютекс - это семафор со значением 1.)
Семафор:
Количество одинаковых бесплатных ключей от туалета. Например, у нас есть четыре туалета с одинаковыми замками и ключами. Счетчик семафоров - счетчик ключей - установлен на 4 в начале (все четыре туалета свободны), затем значение счетчика уменьшается по мере того, как люди входят. Если все туалеты заполнены, т.е. свободных ключей не осталось, счетчик семафоров равен 0. Теперь, когда eq. один человек выходит из туалета, семафор увеличивается до 1 (один свободный ключ) и передается следующему человеку в очереди.
Официально: «Семафор ограничивает количество одновременных пользователей совместно используемого ресурса до максимального числа. Потоки могут запрашивать доступ к ресурсу (уменьшая семафор) и могут сигнализировать, что они закончили использование ресурса (увеличивая семафор). " Ссылка: Библиотека разработчика Symbian
Пытаюсь не показаться глупым, но ничего не могу с собой поделать.
Ваш вопрос должен заключаться в том, в чем разница между мьютексом и семафором? А если быть более точным, следует задать вопрос: «Какая связь между мьютексом и семафором?»
(Я бы добавил этот вопрос, но я на сто процентов уверен, что какой-нибудь чрезмерно усердный модератор закроет его как дубликат, не понимая разницы между различием и отношениями.)
В объектной терминологии мы можем заметить, что:
наблюдение.1 Семафор содержит мьютекс
наблюдение.2 Мьютекс не является семафором, а семафор не является мьютексом.
Есть некоторые семафоры, которые будут действовать как мьютекс, называемые двоичными семафорами, но они, черт возьми, НЕ мьютекс.
Существует специальный ингредиент, называемый Сигнализация (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
не закончили. Одним словом, семафор используется, когда мы заботимся о порядке выполнения многопоточности.
x
и y
, затем рассчитайте z = x + y
. Я знаю, что в java есть CyclicBarrier
. Кроме того, я не уверен, что могу сказать, что mapreduce
это тоже вариант использования семафоров, потому что я не могу этого сделать, reduce
пока все map
s не будут завершены.
Все приведенные выше ответы хорошего качества, но этот просто для запоминания. Название Mutex происходит от Mutually Exclusive, поэтому у вас есть мотивация думать о блокировке мьютекса как о взаимном исключении между двумя, как только по одному, и если я обладал им, вы можете получить его только после того, как я его отпущу. С другой стороны, такого случая не существует, поскольку Семафор похож на светофор (что также означает слово Семафор).
Как было указано, семафор со счетчиком, равным единице, - это то же самое, что и «двоичный» семафор, то же самое, что и мьютекс.
Основное, что я видел семафоры со счетчиком больше одного, - это ситуации производителя / потребителя, в которых у вас есть очередь определенного фиксированного размера.
Тогда у вас есть два семафора. Первый семафор изначально установлен как количество элементов в очереди, а второй семафор установлен на 0. Производитель выполняет операцию P над первым семафором, добавляет в очередь. и выполняет операцию V на втором. Потребитель выполняет операцию P со вторым семафором, удаляет его из очереди, а затем выполняет операцию V над первым.
Таким образом, производитель блокируется всякий раз, когда он заполняет очередь, а потребитель блокируется, когда очередь пуста.
Мьютекс - это особый случай семафора. Семафор позволяет нескольким потокам войти в критическую секцию. При создании семафора вы определяете, как могут быть разрешены потоки в критической секции. Конечно, ваш код должен иметь возможность обрабатывать несколько обращений к этому критическому разделу.
Бинарный семафор и мьютекс разные. С точки зрения ОС двоичный семафор и счетный семафор реализованы одинаково, и двоичный семафор может иметь значение 0 или 1.
Mutex -> Может использоваться только для одной-единственной цели взаимного исключения для критического участка кода.
Семафор -> Может использоваться для решения множества задач. Двоичный семафор может использоваться для сигнализации, а также для решения проблемы взаимного исключения. При инициализации 0 решает проблему сигнализации, а при инициализации 1 решает проблему взаимного исключения .
Когда количество ресурсов больше и их необходимо синхронизировать, мы можем использовать семафор подсчета.
В своем блоге я подробно рассмотрел эти темы.
https://designpatterns-oo-cplusplus.blogspot.com/2015/07/synchronization-primitives-mutex-and.html