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


820

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


11
Они семантически одинаковы, но на практике вы заметите странные различия (особенно в Windows).
Майкл Фукаракис

5
@ Майкл Фукаракис: В чем странные различия?
Филипп

2
Я полагаю, странное не правильное выражение. Мьютекс также поддерживает владение и иногда повторный вход. Это дело в Windows. Кроме того, семафоры в Windows реализованы поверх объектов Event, однако я не уверен в практических последствиях этого.
Майкл Фукаракис

1
Аналогичное обсуждение в stackoverflow.com/questions/4039899/…
Картик Балагуру,

2
@philipxy Отлично спрятал «rn» вместо «m».
Mooncrater

Ответы:


691

Они НЕ одно и то же. Они используются для разных целей!
Хотя оба типа семафоров имеют полное / пустое состояние и используют один и тот же API, их использование сильно отличается.

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

Семафор Mutex «принадлежит» задаче, которая его выполняет. Если задача B попытается передать мьютекс, который в данный момент находится в задаче A, вызов задачи B вернет ошибку и произойдет сбой.

Мьютексы всегда используют следующую последовательность:

  - SemTake
  - Критический раздел
  - SemGive

Вот простой пример:

  Нить A Нить B
   Возьми Мутекс
     доступ к данным
     ... возьми мьютекс <== заблокируешь
     ...
   Предоставить Mutex доступ к данным <== Разблокирует
                                  ...
                                Дайте мьютекс

Двоичный семафор
Двоичный семафор решает совершенно другой вопрос:

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

   Task A                      Task B
   ...                         Take BinSemaphore   <== wait for something
   Do Something Noteworthy
   Give BinSemaphore           do something    <== unblocks

Обратите внимание, что с двоичным семафором B может взять семафор и A дать его.
Опять же, двоичный семафор НЕ защищает ресурс от доступа. Акт «Давать и брать семафор» в корне не связан.
Как правило, для одной и той же задачи не имеет смысла давать один и тот же двоичный семафор.


12
Разве мьютекс не лучше бинарного семафора? Поскольку не имеет смысла, если кто-то снимает блокировку, которую он на самом деле не держит.
Pacerier

111
У них разные цели. Mutex для эксклюзивного доступа к ресурсу. Для синхронизации следует использовать двоичный семафор (например, «Эй, кто-то! Это произошло!»). Двоичный «даритель» просто уведомляет любого «получателя» о том, что произошло.
Бенуа

5
@Pacerier Вы путаете цель. Мьютекс предназначен для защиты критической области. Вы правы, не имеет смысла использовать двоичный семафор. Я обновлю ответ, чтобы объяснить цель каждого.
Бенуа

4
@Benoit Итак, можем ли мы сказать, что Mutex используются для атомарности, а бинарный семафор для перспективы упорядочения, поскольку задача B будет ожидать, пока задача A сообщит о снятии блокировки, которая сама по себе будет обеспечивать упорядочение операций над структурой данных?
Абхи

1
@abhi Это хороший способ посмотреть на Mutex. Однако, в зависимости от операционной системы, на двоичном семафоре может ожидаться более одного получателя. В этом случае только один из клиентов получит бинарный sem. Другие будут ждать следующего. Порядок получения известен или гарантирован? Зависит от ОС.
Бенуа

447
  • Мьютекс может быть освобожден только потоком , который приобрел его .
  • Бинарный семафор может быть передан любым потоком (или процесса).

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

В Windows двоичные семафоры больше похожи на объекты событий, чем на мьютексы.


34
Mutex can be released only by thread that had acquired it- Я только что попробовал с простой программой, основанной на pthread_mutex, поток может разблокировать мьютекс, заблокированный в основном потоке
маргаритка

15
@ warl0ck Согласно man-странице pthread_mutex_lock linux.die.net/man/3/pthread_mutex_lock : "Если тип мьютекса - PTHREAD_MUTEX_ERRORCHECK, то должна быть обеспечена проверка ошибок .... Если поток пытается разблокировать мьютекс, который он имеет не заблокирован или мьютекс, который разблокирован, возвращается ошибка ".
Амит

47
@ warl0ck См. stackoverflow.com/a/5492499/385064 'Pthreads имеет 3 различных типа мьютексов: быстрый мьютекс, рекурсивный мьютекс и мьютекс проверки ошибок. Вы использовали быстрый мьютекс, который по соображениям производительности не будет проверять эту ошибку. Если вы используете мьютекс проверки ошибок в Linux, вы получите ожидаемые результаты ».
FrostNovaZzz

1
В нашем коде мы использовали мьютекс также для целей синхронизации. Поток, который блокирует мьютекс, снова попытался заблокировать мьютекс. Затем он переходит в заблокированное состояние. Мы видели, что мы можем разблокировать его из другого потока. синхронизация между ними. Мы используем только стандарт posix. Так что основное различие между мьютексом и двоичным семафором кажется расплывчатым.
achoora

1
@achoora Я согласен, что неправильно синхронизировать семафор. На самом деле все мьютекс, двоичный семафор, барьер, конвейеры - это разные шаблоны для синхронизации. С точки зрения дизайна мьютекс больше похож на шаблон состояния, где алгоритм, выбранный состоянием, может изменять состояние. Бинарный семафор больше похож на шаблон стратегии, где внешний алгоритм может изменить состояние и, в конечном итоге, алгоритм / стратегия, выбранные для запуска.
Шува

442

Пример туалета - приятная аналогия:

мьютекс:

Это ключ к туалету. Один человек может иметь ключ - занять туалет - в самый раз. Когда закончено, человек дает (освобождает) ключ следующему человеку в очереди.

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

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

Семафор:

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

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


234
... но это касается мьютекса против счетного семафора. Был задан вопрос о бинарном.
Роман Никитченко

24
Хотя то, что говорит Дэвид, верно, но это НЕ ответ на заданный вопрос. Ответ Младена Янковича - это ответ на заданный вопрос, где указывается, что нужно различать «бинарный семафор» и «мьютекс».
Аджит Ганга

13
К сожалению, этот неправильный ответ имеет больше голосов, чем лучший ответ @Benoit
NeonGlow

6
Этот ответ вводит в заблуждение. Его следует сравнивать только с двоичным семафором.
Hemanth

3
Это также демонстрирует проблему с использованием счетного семафора для защиты общего ресурса: если ключи действительно идентичны, и туалет разблокирован с помощью ключа, и нет другого механизма для распределения использования ячейки, то: (1) первый пользователь разблокирует, входит и начинает использовать первую ячейку. (2) следующий пользователь открывает, входит и начинает использовать первую ячейку ...
Технофил

152

Хорошие статьи на эту тему:

Из части 2:

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


Спасибо за ссылку, объяснения там отличные. Ссылка изменилась: feabhas.com/blog/2009/09/… (Используйте <Пред и След> для перехода к двум другим статьям.
Аарон Х.

@ Аарон Я исправил ссылки
Судья Мейгарден,

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

1
+1 за отличные ссылки на статьи. Лучшая статья, объясняющая семафор и мьютекс с помощью слов «что это такое» и «что это делает» computing.llnl.gov/tutorials/pthreads. Я использовал эту статью в качестве своей ссылки за кулисы сцены, которая технически действительно объясняет все о мьютекс / условные выражения и другие конструкции, построенные на их вершине, такие как семафор / барьер / читатель-писатель, но нигде явно и кратко о проблемах, с которыми сталкиваются конструкции. Короче это ссылка. :)
Аджит Ганга

легче понять, чем другие ответы.
BinaryTreeee

102

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

Строго говоря, мьютекс - это механизм блокировки, используемый для синхронизации доступа к ресурсу. Только одна задача (может быть потоком или процессом, основанным на абстракции ОС) может получить мьютекс. Это означает, что с мьютексом будет владение, и только владелец может снять блокировку (мьютекс).

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

Источник: http://www.geeksforgeeks.org/mutex-vs-semaphore/


43

Их семантика синхронизации очень различна:

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

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


23

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

Практическое отличие (с точки зрения окружающих их системных служб) состоит в том, что реализация мьютекса направлена ​​на то, чтобы стать более легким механизмом синхронизации. В оракуле мьютексы известны как защелки, а семафоры - как ожидания .

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

Типичная реализация мьютекса имеет процесс или поток, выполняющий инструкцию test-and-set и оценивающий, установил ли мьютекс что-либо еще. Ключевым моментом здесь является то, что нет взаимодействия с планировщиком , поэтому мы понятия не имеем (и не волнует), кто установил блокировку. Затем мы либо оставляем наш временной интервал и повторяем попытку при повторном планировании задачи, либо выполняем спин-блокировку . Спин-блокировка - это алгоритм вроде:

Count down from 5000:
     i. Execute the test-and-set instruction
    ii. If the mutex is clear, we have acquired it in the previous instruction 
        so we can exit the loop
   iii. When we get to zero, give up our time slice.

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

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

Основной алгоритм семафора выглядит так:

(somewhere in the program startup)
Initialise the semaphore to its start-up value.

Acquiring a semaphore
   i. (synchronised) Attempt to decrement the semaphore value
  ii. If the value would be less than zero, put the task on the tail of the list of tasks waiting on the semaphore and give up the time slice.

Posting a semaphore
   i. (synchronised) Increment the semaphore value
  ii. If the value is greater or equal to the amount requested in the post at the front of the queue, take that task off the queue and make it runnable.  
 iii. Repeat (ii) for all tasks until the posted value is exhausted or there are no more tasks waiting.

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

РЕДАКТИРОВАТЬ: Как справедливо указал Эван, спин-блокировки будут замедлять однопроцессорный компьютер. Вы можете использовать спин-блокировку только на многопроцессорном блоке, потому что на одном процессоре процесс, удерживающий мьютекс, никогда не сбросит его, пока выполняется другая задача. Спин-блокировки полезны только на многопроцессорных архитектурах.


1
Я не думаю, что обычной практикой является использование мьютекса с помощью спин-блокировки. На машине Uni-proc это было бы абсолютно ужасно для производительности.
Эван Теран

Обычно вы используете спин-блокировки только на многопроцессорных системах.
ConcernedOfTunbridgeWells

Даже на SMP, после нескольких вращений вы возвращаетесь к режиму сна / бодрствования с помощью ОС. (Например, futexсуществует системный вызов Linux , чтобы помочь реализации мьютекса / семафора в пользовательском пространстве с низкой задержкой. en.wikipedia.org/wiki/Futex ) В быстром пути без конфликтов, или если ресурс скоро станет доступным, у вас никогда не будет лишних затрат системный вызов. Но вы не тратите больше нескольких микросекунд на ожидание (вращение). Конечно, настройка параметров отката и ожидания спин-цикла зависит от оборудования и рабочей нагрузки, но стандартная библиотека обычно имеет разумные варианты.
Питер Кордес

19

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


"может быть передано другим потоком", что это значит, приведите пример.
Myanju

15

Мьютекс: Предположим, что у нас есть критическая секция, которую T1 хочет получить к ней доступ, затем она следует нижеуказанным шагам. T1:

  1. Замок
  2. Используйте критический раздел
  3. разблокировка

Двоичный семафор: работает на основе сигналов ожидания и сигнала. wait (s) уменьшает значение "s" на единицу, обычно значение "s" инициализируется значением "1", сигнал (ы) увеличивает значение "s" на единицу. если значение "s" равно 1, значит, никто не использует критическую секцию, когда значение равно 0, означает, что критическая секция используется. Предположим, что поток T2 использует критическую секцию, затем следует следующие шаги. T2:

  1. wait (s) // изначально значение s равно единице после вызова wait, его значение уменьшилось на единицу, т.е. 0
  2. Использовать критический раздел
  3. signal (s) // теперь значение s увеличивается и становится 1

Основное различие между Mutex и двоичным семафором заключается в Mutext, если поток блокирует критическую секцию, тогда он должен разблокировать критическую секцию, никакой другой поток не может разблокировать его, но в случае двоичного семафора, если один поток блокирует критическую секцию, используя функцию wait (s), тогда значение из s становится "0", и никто не может получить к нему доступ, пока значение "s" не станет 1, но предположим, что какой-то другой поток вызывает сигнал (ы), а затем значение "s" становится 1, и это позволяет другой функции использовать критическую секцию. следовательно, в двоичном семафорном потоке нет владения.


12

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

  1. Мьютекс может быть освобожден только тем потоком, у которого есть владелец, то есть потоком, который ранее вызывал функцию Wait (или который стал владельцем при создании). Семафор может быть освобожден любым потоком.

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


4
Хороший ответ. В # 2 вы описываете рекурсивный мьютекс - не все мьютексы обязательно являются рекурсивными. Например, cs.wustl.edu/~schmidt/ACE.FAQ.html#Q14
Дан

10

Вы, очевидно, используете мьютекс для блокировки данных в одном потоке, к которым одновременно обращается другой поток. Предположим, что вы только что позвонилиlock() и в процессе доступа к данным. Это означает, что вы не ожидаете, что какой-либо другой поток (или другой экземпляр того же кода потока) получит доступ к тем же данным, заблокированным тем же мьютексом. То есть, если один и тот же код потока выполняется в другом экземпляре потока, он блокирует блокировку, тогдаlock()должен блокировать поток управления там. Это относится к потоку, который использует другой код потока, который также обращается к тем же данным и который также заблокирован тем же мьютексом. В этом случае вы все еще находитесь в процессе доступа к данным, и вам может потребоваться, скажем, еще 15 секунд, чтобы достичь разблокировки мьютекса (чтобы другой поток, блокируемый блокировкой мьютекса, разблокировался и позволил элементу управления доступ к данным). Разрешаете ли вы любой ценой позволить еще одному потоку просто разблокировать тот же мьютекс и, в свою очередь, разрешить потоку, который уже ожидает (блокирует) блокировку мьютекса, разблокировать и получить доступ к данным? Надеюсь, ты понял, что я здесь говорю? Согласно согласованному универсальному определению!

  • с «мьютексом» этого не может быть. Никакая другая тема не может разблокировать блокировку в вашей теме.
  • с «двоичным семафором» это может произойти. Любая другая тема может разблокировать блокировку в вашей теме

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


10

Mutex используются для «Механизмов блокировки». один процесс за раз может использовать общий ресурс

в то время как

Семафоры используются для «Сигнальных механизмов», таких как «Я закончил, теперь могу продолжить»


9

Миф:

Пара статей говорит, что «двоичный семафор и мьютекс одинаковы» или «семафор со значением 1 является мьютексом», но основное отличие в том, что Mutex может быть освобожден только тем потоком, который его получил, в то время как вы можете сигнализировать семафор из любого другого потока

Ключевые моменты:

• Поток может получить более одной блокировки (Mutex).

• Мьютекс может быть заблокирован более одного раза, только если это рекурсивный мьютекс, здесь блокировка и разблокировка для мьютекса должны быть одинаковыми

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

• Двоичный семафор и мьютекс похожи, но не одинаковы.

• Mutex является дорогостоящей операцией из-за протоколов защиты, связанных с ним.

• Основная цель мьютекса - добиться атомарного доступа или блокировки ресурса.


8

Мьютекса контролирует доступ к одному общему ресурсу. Он предоставляет операции для получения () доступа к этому ресурсу и выпуска () его по завершении.

Семафор управляет доступом к общему пулу ресурсов. Он обеспечивает операции Wait () до тех пор, пока один из ресурсов в пуле не станет доступным, и Signal () когда он будет возвращен пулу.

Когда количество ресурсов, которые защищает семафор, больше 1, оно называется счетным семафором . Когда он управляет одним ресурсом, он называется булевым семафором . Булев семафор эквивалентен мьютексу.

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


6

Измененный вопрос - в чем разница между мьютексом и «двоичным» семафором в «Linux»?

Ответ: Ниже приведены различия: i) Область действия. Область действия мьютекса находится в пределах адресного пространства процесса, которое его создало, и используется для синхронизации потоков. Принимая во внимание, что семафор может использоваться в пространстве процессов и, следовательно, он может использоваться для межпроцессной синхронизации.

II) Mutex легкий и быстрее, чем семафор. Futex еще быстрее

iii) Mutex может быть успешно получен одним и тем же потоком несколько раз при условии, что он должен освобождать его одинаковое количество раз. Другой поток, пытающийся получить, заблокирует. Принимая во внимание, что в случае семафора, если тот же процесс пытается получить его снова, он блокируется, поскольку его можно получить только один раз.


я неправ. II) Источник? III) Это зависит.
любопытный парень

6

Разница между двоичным семафором и мьютексом: ВЛАДЕНИЕ: Семафоры могут сигнализироваться (публиковаться) даже от не текущего владельца. Это означает, что вы можете просто отправлять сообщения из любой другой ветки, хотя вы не являетесь их владельцем.

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


5

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


5

http://www.geeksforgeeks.org/archives/9102 обсуждает в деталях.

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

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


4

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


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

1
POSIX имеет специфические требования, поток должен быть разбужен sem_post()для SCHED_FIFOи SCHED_RR(оба из них не по умолчанию): наивысший приоритет потока, и , если есть несколько с тем же приоритетом, нити , которые долго ждали дольше. OpenSolaris в некоторой степени следует этому правилу FIFO даже для обычного планирования. Для glibc и FreeBSD разблокировка простого мьютекса (т.е. не приоритетная защита или наследование приоритетов) и публикация семафора в основном одинаковы, помечая объект как разблокированный, а затем, если могут быть ожидающие потоки, вызывать ядро ​​для пробуждения одного из них.
Джил

4

В окнах разница, как показано ниже. MUTEX: процесс, который успешно выполняет ожидание, должен выполнить сигнал и наоборот. Двоичные семафоры: различные процессы могут выполнять операцию ожидания или сигнала на семафоре.


4

В то время как двоичный семафор может использоваться как мьютекс, мьютекс является более конкретным вариантом использования, так как только процесс, который заблокировал мьютекс, должен его разблокировать. Это ограничение собственности позволяет обеспечить защиту от:

  • Случайный выпуск
  • Рекурсивный тупик
  • Задача Смертельный тупик

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

Например, вы можете включить атрибут проверки ошибок в вашем мьютексе. Ошибка проверки мьютексов возвращается, EDEADLKесли вы попытаетесь заблокировать один и тот же дважды иEPERM если вы разблокируете мьютекс, который не принадлежит вам.

pthread_mutex_t mutex;
pthread_mutexattr_t attr;
pthread_mutexattr_init (&attr);
pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
pthread_mutex_init (&mutex, &attr);

После инициализации мы можем поместить эти проверки в наш код следующим образом:

if(pthread_mutex_unlock(&mutex)==EPERM)
 printf("Unlock failed:Mutex not owned by this thread\n");

4

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

Когда мы пытаемся дать семафор, не беря его, он проходит. Но когда вы пытаетесь дать мьютекс, не беря его, это не получается. Я проверил это на платформе Windows. Разрешите USE_MUTEX для запуска того же кода, используя MUTEX.

#include <stdio.h>
#include <windows.h>
#define xUSE_MUTEX 1
#define MAX_SEM_COUNT 1

DWORD WINAPI Thread_no_1( LPVOID lpParam );
DWORD WINAPI Thread_no_2( LPVOID lpParam );

HANDLE Handle_Of_Thread_1 = 0;
HANDLE Handle_Of_Thread_2 = 0;
int Data_Of_Thread_1 = 1;
int Data_Of_Thread_2 = 2;
HANDLE ghMutex = NULL;
HANDLE ghSemaphore = NULL;


int main(void)
{

#ifdef USE_MUTEX
    ghMutex = CreateMutex( NULL, FALSE, NULL);
    if (ghMutex  == NULL) 
    {
        printf("CreateMutex error: %d\n", GetLastError());
        return 1;
    }
#else
    // Create a semaphore with initial and max counts of MAX_SEM_COUNT
    ghSemaphore = CreateSemaphore(NULL,MAX_SEM_COUNT,MAX_SEM_COUNT,NULL);
    if (ghSemaphore == NULL) 
    {
        printf("CreateSemaphore error: %d\n", GetLastError());
        return 1;
    }
#endif
    // Create thread 1.
    Handle_Of_Thread_1 = CreateThread( NULL, 0,Thread_no_1, &Data_Of_Thread_1, 0, NULL);  
    if ( Handle_Of_Thread_1 == NULL)
    {
        printf("Create first thread problem \n");
        return 1;
    }

    /* sleep for 5 seconds **/
    Sleep(5 * 1000);

    /*Create thread 2 */
    Handle_Of_Thread_2 = CreateThread( NULL, 0,Thread_no_2, &Data_Of_Thread_2, 0, NULL);  
    if ( Handle_Of_Thread_2 == NULL)
    {
        printf("Create second thread problem \n");
        return 1;
    }

    // Sleep for 20 seconds
    Sleep(20 * 1000);

    printf("Out of the program \n");
    return 0;
}


int my_critical_section_code(HANDLE thread_handle)
{

#ifdef USE_MUTEX
    if(thread_handle == Handle_Of_Thread_1)
    {
        /* get the lock */
        WaitForSingleObject(ghMutex, INFINITE);
        printf("Thread 1 holding the mutex \n");
    }
#else
    /* get the semaphore */
    if(thread_handle == Handle_Of_Thread_1)
    {
        WaitForSingleObject(ghSemaphore, INFINITE);
        printf("Thread 1 holding semaphore \n");
    }
#endif

    if(thread_handle == Handle_Of_Thread_1)
    {
        /* sleep for 10 seconds */
        Sleep(10 * 1000);
#ifdef USE_MUTEX
        printf("Thread 1 about to release mutex \n");
#else
        printf("Thread 1 about to release semaphore \n");
#endif
    }
    else
    {
        /* sleep for 3 secconds */
        Sleep(3 * 1000);
    }

#ifdef USE_MUTEX
    /* release the lock*/
    if(!ReleaseMutex(ghMutex))
    {
        printf("Release Mutex error in thread %d: error # %d\n", (thread_handle == Handle_Of_Thread_1 ? 1:2),GetLastError());
    }
#else
    if (!ReleaseSemaphore(ghSemaphore,1,NULL) )      
    {
        printf("ReleaseSemaphore error in thread %d: error # %d\n",(thread_handle == Handle_Of_Thread_1 ? 1:2), GetLastError());
    }
#endif

    return 0;
}

DWORD WINAPI Thread_no_1( LPVOID lpParam ) 
{ 
    my_critical_section_code(Handle_Of_Thread_1);
    return 0;
}


DWORD WINAPI Thread_no_2( LPVOID lpParam ) 
{
    my_critical_section_code(Handle_Of_Thread_2);
    return 0;
}

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


Если вы прочитаете другие ответы, станет ясно, что концепция «владения» имеет смысл только с мьютексами, а не с семафорами. Семафоры могут использоваться для таких вещей, как поток, позволяющий другим потокам знать, что обработка фрагмента данных завершена; результаты готовы к прочтению.
Питер Кордес

2

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


2

Mutex

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

семафор

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


1

Ответ может зависеть от целевой ОС. Например, по крайней мере одна из знакомых мне реализаций RTOS позволит выполнять несколько последовательных операций «get» для одного мьютекса ОС, при условии, что все они находятся в одном и том же контексте потока. Множественное получение должно быть заменено равным количеством операций, прежде чем другому потоку будет разрешено получить мьютекс. Это отличается от двоичных семафоров, для которых допускается только одно получение, независимо от контекста потока.

Идея такого мьютекса заключается в том, что вы защищаете объект, позволяя изменять данные только в одном контексте. Даже если поток получает мьютекс и затем вызывает функцию, которая дополнительно изменяет объект (и получает / помещает мьютекс защитника вокруг своих собственных операций), операции все равно должны быть безопасными, поскольку все они происходят в одном потоке.

{
    mutexGet();  // Other threads can no longer get the mutex.

    // Make changes to the protected object.
    // ...

    objectModify();  // Also gets/puts the mutex.  Only allowed from this thread context.

    // Make more changes to the protected object.
    // ...

    mutexPut();  // Finally allows other threads to get the mutex.
}

Конечно, при использовании этой функции вы должны быть уверены, что все обращения в пределах одного потока действительно безопасны!

Я не уверен, насколько распространен этот подход или применяется ли он за пределами систем, с которыми я знаком. Пример такого мьютекса см. В RTOS ThreadX.


2
Тип мьютекса, о котором вы говорите, называется «рекурсивный мьютекс», и его следует избегать, поскольку он медленный и имеет тенденцию продвигать плохой дизайн: (см. David Butenhof: zaval.org/resources/library/butenhof1.html )
gaspard

Согласовано. В этой конкретной ОС я использую службу мьютекса, где хочу прояснить, что код предназначен для «взаимного исключения», а не для подсчета ссылок, но я не использую рекурсивную функцию из-за страха отвратительного раскручивания. Тем не менее, в контексте вопроса, это важное различие между «мьютексом» и «двоичным семафором».
Кейси Баркер

1

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


Что такое владение? Вы имеете в виду, что контекст, который приобретает мьютекс, может его только обнаружить. ??
Раульп

1

Как уже упоминали многие, мьютекс используется для защиты критического фрагмента кода (критический раздел AKA). Вы получите мьютекс (блокировку), войдите в критический раздел и освободите мьютекс (разблокировку) в одном потоке .

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


1

Лучшее решение

Единственная разница

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

2. Семафор -> Нет собственности т.е. если один поток вызывает semwait (s), любой другой поток может вызвать sempost (s), чтобы снять блокировку.


1

MUTEX

До недавнего времени единственным спящим замком в ядре был семафор. Большинство пользователей семафоров создавали семафор со счетчиком один и рассматривали их как блокировку взаимного исключения - спящую версию спин-блокировки. К сожалению, семафоры являются довольно общими и не накладывают никаких ограничений на использование. Это делает их полезными для управления эксклюзивным доступом в непонятных ситуациях, таких как сложные танцы между ядром и пользовательским пространством. Но это также означает, что более простую блокировку сделать труднее, а отсутствие принудительных правил делает невозможным любой вид автоматической отладки или применения ограничений. В поисках более простого спящего замка разработчики ядра представили мьютекс. Да, как вы уже привыкли, это запутанное имя. Давайте уточним. Термин «мьютекс» - это общее имя для обозначения любого спящего замка, который обеспечивает взаимное исключение, такой как семафор со счетчиком использования одного. В последних ядрах Linux собственное существительное «mutex» теперь также является особым типом спящего замка, который реализует взаимное исключение. То есть мьютекс - это мьютекс.

Простота и эффективность мьютекса проистекают из дополнительных ограничений, которые он накладывает на своих пользователей сверх того, что требует семафор. В отличие от семафора, который реализует самое основное поведение в соответствии с оригинальным дизайном Дейкстры, мьютекс имеет более строгий и узкий вариант использования: n Одновременно только одна задача может содержать мьютекс. То есть счетчик использования мьютекса всегда один.

  1. Тот, кто заблокировал мьютекс, должен разблокировать его. То есть вы не можете заблокировать мьютекс в одном контексте, а затем разблокировать его в другом. Это означает, что мьютекс не подходит для более сложной синхронизации между ядром и пользовательским пространством. В большинстве случаев, однако, чисто блокировать и разблокировать из того же контекста.
  2. Рекурсивные блокировки и разблокировки не допускаются. То есть вы не можете рекурсивно получить тот же мьютекс и не можете разблокировать разблокированный мьютекс.
  3. Процесс не может выйти, удерживая мьютекс.
  4. Мьютекс не может быть получен обработчиком прерывания или нижней половиной, даже с mutex_trylock ().
  5. Мьютекс может управляться только через официальный API: он должен быть инициализирован с помощью методов, описанных в этом разделе, и не может быть скопирован, инициализирован вручную или повторно инициализирован.

[1] Разработка ядра Linux, третье издание Роберт Лав


1

Я думаю, что большинство ответов здесь сбивают с толку, особенно те, которые говорят, что мьютекс может быть освобожден только процессом, который его удерживает, но семафор может сигнализироваться любым процессом. Приведенная выше строка является довольно размытой с точки зрения семафора. Чтобы понять, мы должны знать, что существует два вида семафоров: один называется счетным семафором, а другой - двоичным семафором. При подсчете семафор обрабатывает доступ к n количеству ресурсов, где n может быть определено перед использованием. Каждый семафор имеет переменную count, которая хранит счетчик количества используемых ресурсов, изначально он равен n. Каждый процесс, который хочет использовать ресурс, выполняет операцию wait () с семафором (тем самым уменьшая количество). Когда процесс освобождает ресурс, он выполняет операцию release () (увеличивая счетчик). Когда счет становится 0, все ресурсы используются. После этого процесс ожидает, пока счетчик станет больше 0. Теперь здесь есть перехват, только процесс, который содержит ресурс, может увеличить счет, никакой другой процесс не может увеличить счет, только процессы, содержащие ресурс, могут увеличить счет и процесс. ожидание семафора снова проверяет, и когда он видит доступный ресурс, он снова уменьшает количество. Таким образом, с точки зрения бинарного семафора, только процесс, содержащий семафор, может увеличить счетчик, и счет остается нулевым, пока он не прекратит использовать семафор и не увеличит счет, и другой процесс получит возможность доступа к семафору. Теперь здесь есть ловушка, только процесс, который содержит ресурс, может увеличить счетчик, никакой другой процесс не может увеличить счет, только процесс, содержащий ресурс, может увеличить счетчик, и процесс, ожидающий семафор, снова проверяет, и когда он видит ресурс, доступный, это уменьшает счет снова. Таким образом, с точки зрения бинарного семафора, только процесс, содержащий семафор, может увеличить счетчик, и счет остается нулевым, пока он не прекратит использовать семафор и не увеличит счет, и другой процесс получит возможность доступа к семафору. Теперь здесь есть ловушка, только процесс, который содержит ресурс, может увеличить счетчик, никакой другой процесс не может увеличить счет, только процесс, содержащий ресурс, может увеличить счетчик, и процесс, ожидающий семафор, снова проверяет, и когда он видит ресурс, доступный, это уменьшает счет снова. Таким образом, с точки зрения бинарного семафора, только процесс, содержащий семафор, может увеличить счетчик, и счет остается нулевым, пока он не прекратит использовать семафор и не увеличит счет, и другой процесс получит возможность доступа к семафору.

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

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