Когда мы должны использовать мьютекс, а когда мы должны использовать семафор


Ответы:


93

Вот как я запоминаю, когда что использовать -

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

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

Spinlock: используйте спин-блокировку, если вы действительно хотите использовать мьютекс, но вашему потоку не разрешено спать. например: обработчик прерывания в ядре ОС никогда не должен спать. Если это произойдет, система зависнет / выйдет из строя. Если вам нужно вставить узел в глобально общий связанный список из обработчика прерывания, приобретите спин-блокировку - вставьте узел - освободите спин-блокировку.


1
to add to: семафоры и мьютекс - это два способа обеспечить синхронизацию. семафор может быть больше связан с сигнализацией (например, сценарий проблемы производителя и потребителя), а мьютекс может быть больше связан с разрешением доступа к одному за раз (несколько запросов на доступ к общему ресурсу, но только один предоставляется за раз). [хорошая статья: geeksforgeeks.org/mutex-vs-semaphore/]
parasrish

57

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

Его можно рассматривать как эквивалент обычного семафора подсчета (со счетом один) и требования, чтобы он мог быть освобожден только тем же потоком, который его заблокировал (a) .

С другой стороны, семафор имеет произвольный счетчик и может быть заблокирован этим множеством шкафчиков одновременно. И у него может не быть требования, чтобы он был выпущен тем же потоком, который потребовал его (но, если нет, вы должны тщательно отслеживать, кто в настоящее время несет за это ответственность, как и выделенная память).

Итак, если у вас есть несколько экземпляров ресурса (скажем, три ленточных накопителя), вы можете использовать семафор со счетчиком 3. Обратите внимание, что это не говорит вам, какой из этих ленточных накопителей у вас есть, просто то, что у вас есть определенное количество.

Также с помощью семафоров один шкафчик может заблокировать несколько экземпляров ресурса, например, для копирования с ленты на ленту. Если у вас есть один ресурс (скажем, область памяти, которую вы не хотите повреждать), мьютекс более подходит.

Эквивалентные операции:

Counting semaphore          Mutual exclusion semaphore
--------------------------  --------------------------
  Claim/decrease (P)                  Lock
  Release/increase (V)                Unlock

Кроме того: если вы когда-нибудь задумывались над причудливыми буквами, используемыми для запроса и выпуска семафоров, то это потому, что изобретатель был голландцем. Probeer te verlagen означает пытаться уменьшить, а verhogen - увеличить.


(а) ... или его можно рассматривать как нечто совершенно отличное от семафора, что может быть безопаснее, учитывая их почти всегда разные способы использования.


Хорошо, я тоже наткнулся на двоичный семафор. Когда нам нужно использовать бинарный семафор, а когда - мьютекс?
Картик Балагуру

Концептуально двоичный семафор - это мьютекс, и он эквивалентен обычному семафору с единичным счетом. Могут быть различия в реализациях концепции, таких как эффективность или право собственности на ресурс (может быть выпущен кем-то, кроме заявителя, с чем я не согласен с BTW - ресурс должен быть выпущен только тем потоком, который потребовал его ).
paxdiablo

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

1
Они решают конкретную проблему. Тот факт, что проблема, которую они решают, - это люди, которые не очень хорошо разбираются в мьютексах, ни в коем случае не должен умалять решение :-)
paxdiablo

5
Мьютекс полностью отличается от двоичного семафора. Извините, но это определение неверно
Пер Стритцингер

49

Очень важно понимать, что мьютекс - это не семафор со счетом 1!

По этой причине существуют такие вещи, как двоичные семафоры (которые на самом деле являются семафорами со счетом 1).

Разница между мьютексом и двоичным семафором заключается в принципе владения:

Мьютекс приобретается задачей и, следовательно, также должен быть освобожден этой же задачей. Это позволяет исправить несколько проблем с бинарными семафорами (случайное освобождение, рекурсивная тупиковая ситуация и инверсия приоритета).

Предостережение: я написал «делает это возможным», если и как эти проблемы будут устранены, зависит от реализации ОС.

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

Поэтому я рекомендую: если у вас есть чисто реализованные мьютексы и условные переменные (например, с потоками POSIX), используйте их.

Используйте семафоры, только если они точно подходят для задачи, которую вы пытаетесь решить, не пытайтесь создавать другие примитивы (например, rw-блокировки из семафоров, используйте для них мьютексы и условные переменные)

Есть много недопонимания мьютексов и семафоров. Лучшее объяснение, которое я нашел до сих пор, содержится в этой статье из трех частей:

Мьютекс против семафоров - Часть 1: семафоры

Мьютекс против семафоров - Часть 2: Мьютекс

Мьютекс против семафоров - Часть 3 (заключительная часть): Проблемы взаимного исключения


URL-адреса этого сайта содержат забавные символы и поэтому не работают ... Я работаю над этим
Пер Стритцингер

13

Хотя ответ @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 для дальнейших объяснений.


2
Ты прав. Даже если вы используете семафор с единичным счетчиком, вы подразумеваете нечто большее, чем если бы вы использовали мьютекс.
Omnifarious

Я не уверен, что согласен с этим, хотя я не согласен настолько сильно, что я буду отрицать вас :-) Вы говорите, что шаблон использования семафоров заключается в уведомлении потоков, но это именно то, что делают мьютексы, когда есть другой поток, ожидающий на нем, и что именно семафоры не работают, когда нет потоков sema_wait:-) На мой взгляд, они оба относятся к ресурсам, а уведомление, передаваемое другим потокам, является побочным эффектом (очень важным с точки зрения производительности) защита.
paxdiablo

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/… )

@paxdiablo: есть одно важное различие между этим двоичным семафором мьютекса - это поддержание счетчика ссылок. Мьютекс, или вы можете сказать, что любой условный мьютекс не поддерживает счетчик, связанный с блокировкой, где семпахор используется для поддержания счетчика. Таким образом, sem_wait и sem_post поддерживают счет.
Prak

9

См. «Пример туалета» - http://pheatt.emporia.edu/courses/2010/cs557f10/hand07/Mutex%20vs_%20Semaphore.htm :

Мьютекс:

Это ключ от туалета. Один человек может иметь ключ - занимать туалет - одновременно. По окончании человек дает (освобождает) ключ следующему человеку в очереди.

Официально: «Мьютексы обычно используются для сериализации доступа к разделу реентерабельного кода, который не может выполняться одновременно более чем одним потоком. Объект мьютекса позволяет только одному потоку войти в контролируемый раздел, вынуждая другие потоки, которые пытаются получить доступ к этот раздел, чтобы ждать, пока первый поток не выйдет из этого раздела ". Ссылка: Библиотека разработчика Symbian

(На самом деле мьютекс - это семафор со значением 1.)

Семафор:

Количество одинаковых бесплатных ключей от туалета. Например, у нас есть четыре туалета с одинаковыми замками и ключами. Счетчик семафоров - счетчик ключей - установлен на 4 в начале (все четыре туалета свободны), затем значение счетчика уменьшается по мере того, как люди входят. Если все туалеты заполнены, т.е. свободных ключей не осталось, счетчик семафоров равен 0. Теперь, когда eq. один человек выходит из туалета, семафор увеличивается до 1 (один свободный ключ) и передается следующему человеку в очереди.

Официально: «Семафор ограничивает количество одновременных пользователей совместно используемого ресурса до максимального числа. Потоки могут запрашивать доступ к ресурсу (уменьшая семафор) и могут сигнализировать, что они закончили использование ресурса (увеличивая семафор). " Ссылка: Библиотека разработчика Symbian


7

Пытаюсь не показаться глупым, но ничего не могу с собой поделать.

Ваш вопрос должен заключаться в том, в чем разница между мьютексом и семафором? А если быть более точным, следует задать вопрос: «Какая связь между мьютексом и семафором?»

(Я бы добавил этот вопрос, но я на сто процентов уверен, что какой-нибудь чрезмерно усердный модератор закроет его как дубликат, не понимая разницы между различием и отношениями.)

В объектной терминологии мы можем заметить, что:

наблюдение.1 Семафор содержит мьютекс

наблюдение.2 Мьютекс не является семафором, а семафор не является мьютексом.

Есть некоторые семафоры, которые будут действовать как мьютекс, называемые двоичными семафорами, но они, черт возьми, НЕ мьютекс.

Существует специальный ингредиент, называемый Сигнализация (posix использует condition_variable для этого имени), необходимый для создания семафора из мьютекса. Думайте об этом как об источнике уведомлений. Если два или более потока подписаны на один и тот же источник уведомлений, то можно отправить им сообщение либо ОДНОМУ, либо ВСЕМ для пробуждения.

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

Здесь смятение вливается, как дождливый сезон.

Семафор со счетчиком, который может быть 0 или 1, НЕ является мьютексом.

Mutex имеет два состояния (0,1) и одно владение (задача). Семафор имеет мьютекс, несколько счетчиков и условную переменную.

Теперь используйте свое воображение, и каждая комбинация использования счетчика и времени подачи сигнала может создать один вид семафора.

  1. Одиночный счетчик со значением 0 или 1 и сигнализация, когда значение переходит в 1 И затем разблокирует одного из парней, ожидающих сигнала == Двоичный семафор

  2. Единый счетчик со значением от 0 до N и сигнализация, когда значение становится меньше N, и блокировка / ожидание, когда значение равно N == Семафор подсчета

  3. Одиночный счетчик со значением от 0 до N и сигнализация, когда значение переходит в N, и блокирует / ожидает, когда значения меньше N == Семафор барьера (ну, если они не вызывают его, то должны.)

Теперь к вашему вопросу, когда что использовать. (ИЛИ правильный вопрос версии 3, когда использовать мьютекс, а когда использовать двоичный семафор, поскольку нет сравнения с небинарным семафором.) Используйте мьютекс, если 1. вам нужно настраиваемое поведение, которое не обеспечивается двоичным семафор, например спин-блокировка, быстрая блокировка или рекурсивная блокировка. Обычно мьютексы можно настраивать с помощью атрибутов, но настройка семафора - это не что иное, как написание нового семафора. 2. вам нужен легкий ИЛИ более быстрый примитив

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

Если вы не понимаете, что предоставляется вашей реализацией двоичного семафора, то, IMHO, используйте мьютекс.

И, наконец, прочтите книгу, а не полагайтесь только на ТАК.


5

Я думаю, что вопрос должен заключаться в разнице между мьютексом и двоичным семафором.

Mutex = Это механизм блокировки владения, только поток, получивший блокировку, может снять блокировку.

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


5

Мьютекс предназначен для защиты общего ресурса.
Семафор предназначен для отправки потоков.

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


Продажа билетов - отличный пример. Пример семафора немного неясен (по крайней мере, для меня).
прайагупд

1
Пример семафора @prayagupd - создание потоков в определенном порядке, тогда как продажа билетов не требует никакого порядка. Если есть три человека: a, b и c. Когда они приходят покупать билеты, нас совершенно не волнует порядок покупки билетов. Однако, если мы сделаем такой расчет: по x = getx(); y = gety(); z = x + y;какой-то причине мы используем три потока для выполнения трех вещей, теперь порядок потоков очень важен, потому что мы не можем сделать, x + yпока getxи getyне закончили. Одним словом, семафор используется, когда мы заботимся о порядке выполнения многопоточности.
Ив

попался. Похоже на барьер . Я могу сказать, что дождитесь завершения потоков xи y, затем рассчитайте z = x + y. Я знаю, что в java есть CyclicBarrier. Кроме того, я не уверен, что могу сказать, что mapreduceэто тоже вариант использования семафоров, потому что я не могу этого сделать, reduceпока все maps не будут завершены.
прайагупд

@prayagupd Да. Вы можете так сказать.
Ив

2

Все приведенные выше ответы хорошего качества, но этот просто для запоминания. Название Mutex происходит от Mutually Exclusive, поэтому у вас есть мотивация думать о блокировке мьютекса как о взаимном исключении между двумя, как только по одному, и если я обладал им, вы можете получить его только после того, как я его отпущу. С другой стороны, такого случая не существует, поскольку Семафор похож на светофор (что также означает слово Семафор).


1

Как было указано, семафор со счетчиком, равным единице, - это то же самое, что и «двоичный» семафор, то же самое, что и мьютекс.

Основное, что я видел семафоры со счетчиком больше одного, - это ситуации производителя / потребителя, в которых у вас есть очередь определенного фиксированного размера.

Тогда у вас есть два семафора. Первый семафор изначально установлен как количество элементов в очереди, а второй семафор установлен на 0. Производитель выполняет операцию P над первым семафором, добавляет в очередь. и выполняет операцию V на втором. Потребитель выполняет операцию P со вторым семафором, удаляет его из очереди, а затем выполняет операцию V над первым.

Таким образом, производитель блокируется всякий раз, когда он заполняет очередь, а потребитель блокируется, когда очередь пуста.


1

Мьютекс - это особый случай семафора. Семафор позволяет нескольким потокам войти в критическую секцию. При создании семафора вы определяете, как могут быть разрешены потоки в критической секции. Конечно, ваш код должен иметь возможность обрабатывать несколько обращений к этому критическому разделу.


-1

Бинарный семафор и мьютекс разные. С точки зрения ОС двоичный семафор и счетный семафор реализованы одинаково, и двоичный семафор может иметь значение 0 или 1.

Mutex -> Может использоваться только для одной-единственной цели взаимного исключения для критического участка кода.

Семафор -> Может использоваться для решения множества задач. Двоичный семафор может использоваться для сигнализации, а также для решения проблемы взаимного исключения. При инициализации 0 решает проблему сигнализации, а при инициализации 1 решает проблему взаимного исключения .

Когда количество ресурсов больше и их необходимо синхронизировать, мы можем использовать семафор подсчета.

В своем блоге я подробно рассмотрел эти темы.

https://designpatterns-oo-cplusplus.blogspot.com/2015/07/synchronization-primitives-mutex-and.html

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.