Обсуждение:Мьютекс

Последнее сообщение: 2 года назад от Serge3leo в теме «Проблемы раздела "Детали реализации"»

CreateMutex/ReleaseMutex - функции WinAPI. Поэтому некорректно приводить их в тексте, говоря при этом, что это системные вызовы. При том еще ссылаясь в дальнейшем, что в каждой ОС свои функции. Т.о. получилась каша. 95.158.255.179 09:44, 15 декабря 2010 (UTC)Ответить

Переделал с обобщением. Так лучше? Netch 08:00, 20 декабря 2010 (UTC)Ответить

Неточное определение мьютекса в первом абзаце править

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

Например, ISO/IEC 14882:2011(E) (C++11), даёт следующее определение мьютекса исходя из его свойств:

A mutex object facilitates protection against data races and allows safe synchronization of data between execution agents (30.2.5). An execution agent owns a mutex from the time it successfully calls one of the lock functions until it calls unlock. Mutexes can be either recursive or non-recursive, and can grant simultaneous ownership to one or many execution agents. The mutex types supplied by the standard library provide exclusive ownership semantics: only one thread may own the mutex at a time. Both recursive and non-recursive mutexes are supplied.

Конечно, чаще всего мы имеем дело с обычными мьютексами (Си11, C++11, POSIX, WinAPI), которые похожи на "одноместный" семафор. Однако мьютексы значительно проще в реализации на типичных платформах, чем семафоры.

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

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

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

Мью́текс (англ. mutex, от mutual exclusion — "взаимное исключение") — программный объект предназначенный для исключения состояния гонок и безопасной синхронизации одновременно выполняющихся потоков определённым образом обращающихся к совместным данным.

Сергей Леонтьев, Крипто-Про 22:57, 4 февраля 2013 (UTC)Ответить

  • Всё слишком путано получается с мьютексами. По части теории классически они определяются именно как эксклюзивное владение блокировкой и именно между потоками. Но в реализациях мьютексами могут назвать, насколько понимаю, и бинарные семафоры, и блокировки чтения-записи, иногда и спин-блокировки, что стирает границы между разными примитивами и алгоритмами. Предлагаю всё же рассматривать shared mutex'ы в рамках блокировок чтения-записи, а в базовом определении мьютекса описать классический примитив синхронизации, отдельно сделав говорки. Или дать два определения, одно — классическое, а другое — обобщающее. -- D6194c-1cc (обс.) 20:13, 20 июня 2020 (UTC)Ответить
    • std::shared_mutex предназначен для ассоциации с std::conditional_variable_any, поэтому их в стандарте и назвали "мьютексами", а, скажем, POSIX блокировки чтения/записи (pthread_rwlock_*()) не имеют таковой ассоциации с условными переменными и не имеют слова "мьютекс" в своём названии Сергей Леонтьев, Крипто-Про (обс.) 02:20, 21 июня 2020 (UTC)Ответить
  • Касательно общих или разделяемых мьютексов сделал оговорку в базовом определении. -- D6194c-1cc (обс.) 20:43, 20 июня 2020 (UTC)Ответить
    • Участник:D6194c-1cc, Ваша правка https://ru.wikipedia.org/w/index.php?title=Мьютекс&diff=prev&oldid=107757133 с заменой "Мьютекс отличается от спинлока тем, что планировщик переводит ожидающие доступа к мьютексу потоки в пассивное состояние" на "От спинлока мьютекс отличается передачей управления планировщику при невозможности захвата мьютекса потоком" немного неточна, т.к. практически все современные спинлоки используют инструкции типа SMT PAUSE (REP NOP, для x86, т.е. обращаются к "аппаратному планировщику"), но часто ж они обращаются и к "планировщику потоков", скажем, FreeBSD pthread_spin_lock() вызывает pthread_yield(), а Solaris pthread_spin_lock() вызывает no_preempt(self)/preempt(self). Сергей Леонтьев, Крипто-Про (обс.) 02:03, 21 июня 2020 (UTC)Ответить
      • Я не знаю, что там за особенная модификация glibc в FreeBSD или Solaris, но в исходниках glibc для разных архитектур обычная спин-блокировка с активным ожиданием. NOP тоже смысла не имеет, поскольку нет смысла заменять рабочий код на пустышку, это не даёт никаких преимуществ, а вот задержки добавит. И про какие-либо «аппаратные планировщики» я никогда не слышал, процессор просто «последовательно» исполняет код, а его внутренняя кухня нам уже не интересна. Если заменить в спин-блокировке активное ожидание на обращение к планировщику, это уже мьютекс получится, а не спин-блокировка. -- D6194c-1cc (обс.) 07:38, 21 июня 2020 (UTC)Ответить
      • Про PAUSE почитал немного, это не более чем подсказка процессору для оптимизации его работы, к планировщику не имеет отношения. -- D6194c-1cc (обс.) 07:52, 21 июня 2020 (UTC)Ответить
        • Ну как не имеет, по этой команде, ядро процессора переключается на соседний поток "гипертрединга" (или соседние потоки, для Sparc/Power/Intel Xeon Phi). Сергей Леонтьев, Крипто-Про (обс.) 09:05, 21 июня 2020 (UTC)Ответить
          • Внутренняя реализация нас не интересует, и никто никуда не переключается, что за заявления? Гипертрединг работает по принципу распараллеливания некоторых инструкций, причём тут PAUSE?
        • FreeBSD, Solaris, как и macOS с Windows, в базовых вариантах glibc не имеют, а вот спинлоки имеют. И они устроены, естественно, немного иначе и немного лучше, чем в glibc. В частности, FreeBSD pthread_spin_lock() вызывает pthread_yield() практически сразу, в случае если выделен один процессор, либо через 10000 итераций ожидания, в случае если выделено несколько процессоров. В libc Solaris у спинлоков есть свои фокусы с планировщиком, ввиду реализации многопоточности вида M*N.
          • Боюсь, что для подобных противоречащих здравому смыслу утверждений про реализации pthreads необходимо предъявить источники (ссылка на сорцы или специализированные форки, или что у Вас там). -- D6194c-1cc (обс.) 10:49, 21 июня 2020 (UTC)Ответить
        • Поэтому некорректно разделять мьютексы и спинлоки "по обращению к планировщику", в общем случае и те и другие обращаются, только за разным. А корректное и важное различие состоит в том, что используется ли "активное ожидание" или "пассивное ожидание", т.к. по этой причине мьютексы нельзя использовать в обработчиках сигналов и прерываний, а спинлоки можно, хотя и осторожно. Сергей Леонтьев, Крипто-Про (обс.) 09:05, 21 июня 2020 (UTC)Ответить
          • Во время активного ожидания обращение к планировщику происходит разве что при переключении контекста, но это не в самой реализации спин-блокировки, а на уровне ОС, поэтому в расчёт это брать нет необходимости. Пассивное же ожидание слишком размытый термин, на мой взгляд, и так или иначе предполагает планировщик. -- D6194c-1cc (обс.) 10:49, 21 июня 2020 (UTC)Ответить

Мьютекс это не семафор править

Мьютекс создаёт взаимоисключающий доступ, т.е. только одному потоку, семафоры создают доступ более одному потоку, при этом есть счетчик, у мьютикса его нет. Плюс у мьютекса есть понятие владельца. Вот еще: http://blog.feabhas.com/2009/09/mutex-vs-semaphores-%E2%80%93-part-1-semaphores/ http://www.barrgroup.com/Embedded-Systems/How-To/RTOS-Mutex-Semaphore

46.251.75.242 16:09, 20 августа 2013 (UTC) Евгений ЕвгеньевичОтветить

Проблемы раздела "Детали реализации" править

Подраздел "На уровне операционных систем" описывает состояние дел только для Linux, в Windows, FreeBSD, Solaris и AIX имеются кардинальные отличия.

Подразделы "В архитектурах x86 и x86_64" и "В архитектуре ARM", по сути, описывают спин-блокировки. Оговорка "Передача управления планировщику является достаточно быстрой операцией..." ошибочна, особенно ввиду того, что в одном цикле ожидания она может происходить многократно. Этот метод реализации мютекса практически не применяется.

Предлагаю:

  • Подразделы "В архитектурах x86 и x86_64" и "В архитектуре ARM" перенести в спин-блокировки;
  • Подраздел "На уровне операционных систем", либо расширить, либо вообще удалить раздел "Детали реализации", как устаревший и не имеющий фундаментальную ценность.

Сергей Леонтьев, Крипто-Про (обс.) 10:44, 31 августа 2021 (UTC)Ответить

  • Нет, задумка раздела была в том, чтобы показать, как мьютексы реализуются на уровне операционной системы и на уровне процессора. Это цельный раздел, который должен подводить читателя с более высокого уровня в более низкий. Если мы не смогли захватить блокировку атомарно, то процесс/поток уже на уровне механизмов ОС попадает в список ожидающих. Аналогично, если блокировка снимается, сигнализируются ожидающие задачи. Механизм сигнализации к спин-локам не относится. -- D6194c-1cc (обс.) 18:17, 31 августа 2021 (UTC)Ответить
    • Два вопроса: это кому-нибудь нужно? Поясню, свойства мьютексов (такие как: справедливость при захвате или случайность, инверсия приоритетов и т.п.) определяются планировщиком ОС (или в Solaris и некоторых версиях FreeBSD для потоков N*M, ещё и планировщиком потоков), поэтому, в отличие от спин-блокировок не возникает особой необходимости создавать собственные мьютексы на коленке. Да, даже если и возникает, то эта работа связана с подробным погружением в потроха ОС. А вот в разделе спин-блокировок это дело пока полезное, т.к. пока ни в одном API нет всех полезных вариантов спин-блокировок. Сергей Леонтьев, Крипто-Про (обс.) 09:27, 2 сентября 2021 (UTC)Ответить

Чем мьютексы отличаются от блокировок? править

Сейчас в статье в нескольких местах используются, на мой взгляд, совершенно излишние оговорки вида: "разделяемых мьютексов — shared_mutex и shared_timed_mutex[4], — по факту являющихся блокировками чтения-записи".

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

Во-вторых, мьютекс - это термин, который уже эволюционировал от словосочетания "mutual exclusion", и, на настоящий момент, имеет свой собственный смысл.

Во-третьих, собственно тот же самый вопрос можно поставить относительно Python lock, C++ std::lock, тех же критических секций Win32 и др., варианты:

  1. Нечто является мьютексом, если в АИ называется мьютексом - нормальный подход;
  2. Нечто является мьютексом, если является пассивной эксклюзивной блокировкой имеющей владельца - ненормальный подход, т.к. и, скорее всего, противоречит АИ, и скорее всего, содержит элементы ОРИСС (мы же сами оцениваем выполнение совокупности этих свойств);
  3. Нечто является мьютексом, если является пассивной блокировкой имеющей владельца и может ассоциироваться с условной переменной (conditional variable) - пока неясный подход, т.к. содержит элементы ОРИСС (можно заметить, что связь мьютексов с условными переменными весьма важна).

Получается, что:

  • Python Lock/RLoc ввиду возможной ассоциации с Condition - наверное, можно назвать мьютексами по пп. 2 и 3;
  • Win32 CRITICAL_SECTION (начиная с Vista/W2r8) ввиду SleepConditionVariableCS() - наверное, тоже можно назвать мьютексами по пп. 2 и 3;
  • Win32 SRWLOCK - не знаю, выполняется только п. 3. Я бы назвал его разделяемым мьютексом, но...;
  • С++ std::shared_mutex - однозначно разделяемый мьютекс по пп. 1 и 3;
  • POSIX pthread_rwlock_t - однозначно не является мьютексом, т.к. не выполняется ни один из пунктов.

- Сергей Леонтьев, Крипто-Про (обс.) 08:57, 2 сентября 2021 (UTC)Ответить