2009-09-28 3 views
42

Являются ли некоторые реализации лучше других для конкретных приложений? Есть ли что-то, что можно заработать, выкатываясь самостоятельно?Как реализованы мьютексы?

+7

«Есть ли что-нибудь, что можно заработать, выкатываясь самостоятельно?» Знание? –

+14

«Есть ли что-нибудь, что можно заработать, выкатываясь самостоятельно?» - Да, ошибочный код! ;) –

+5

@Mitch Wheat - Разумеется, нельзя использовать доморощенные библиотеки мьютексов для производственного кода, но многим людям нравится учиться, а писать собственное [приложение x] очень информативно. –

ответ

21

Ознакомьтесь с описанием машинной инструкции Test-and-set в Википедии, в которой говорится о том, как атомные операции выполняются на уровне машины. Я могу представить, что большинство реализаций мьютексов на уровне языка основаны на поддержке на уровне машины, например Test-and-set.

+0

В x86, например, вы можете использовать инструкцию 'xchg' для автоматической замены регистра на память. Часть магазина представляет собой «набор», а часть нагрузки + разветвление на значении регистра - это «тестовая» половина тестовой и заданной операции. И да, это более или менее то, что вы делаете на практике. См. [Эта минимальная реализация спин-блокировки в asm] (https://stackoverflow.com/questions/37241553/locks-around-memory-manipulation-via-inline-assembly/37246263#37246263), которая делает большую часть важных вещей, кроме отступлений чтобы спать в системном вызове после вращения на некоторое время без получения блокировки. –

2

Interlocked.CompareExchange достаточно, чтобы реализовать шпиндельные блоки. Хотя это довольно сложно сделать правильно. См. Раздел Joe Duffy's blog для примера связанных тонкостей.

+0

Мы говорим о языковых агностических решениях здесь, но благодарим за ваши усилия. –

+0

О, ты прав. Я не знаю, почему я думал о .NET. Возможно, из-за других ответов. – Joren

6

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

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

Вокруг базовой логики мьютекса есть обертки, чтобы обернуть его в объект. Затем добавьте еще объекты-обертки, чтобы сделать его доступным вне ядра. А затем еще одну оболочку, чтобы сделать ее доступной в .NET. И тогда несколько программистов напишут свой собственный код обертки вокруг всего этого для своих собственных логических потребностей. Обертки вокруг оберток действительно делают их темной территорией.

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

Насколько я знаю, Windows, Linux и .NET будут использовать мьютексы на уровне ядра/оборудования.

Страница Wikipedia, с которой я связан, объясняет больше о внутренней логике и возможных вариантах реализации. Предпочтительно, мьютекс управляется аппаратным обеспечением, тем самым делая все получение/настройку мьютекса indivisible step. (Просто чтобы убедиться, что система не переключает задачи между ними.)

+0

+1. Хороший ответ. –

+0

Что значит секрет? Не весь ли исходный код ядра Linux доступен в GitHub? –

+0

О, geez. Это было 8 лет назад, когда я это написал! :) Но да, это секрет, поскольку никто не изучает исходный код для мьютексов в ядре Linux. И те, кто действительно проверяет это, как правило, находят сложную дешифровку логики. См. Https://github.com/torvalds/linux/blob/master/kernel/locking/mutex.c для кода Mutex в Linux ... К счастью, он хорошо комментируется. Тем не менее сложный. Как я уже сказал, * немного * секрет ... –

-1

Я использовал Reflector.NET для декомпиляции источника для System.Threading.ReaderWriterLockSlim, который был добавлен в недавнюю версию .NET framework.

В основном используется Interlocked.CompareExchange, Thread.SpinWait и Thread.Sleep для достижения синхронизации. Есть несколько экземпляров EventWaitHandle (объект ядра), которые используются при некоторых обстоятельствах.

Существует также некоторая сложность для поддержки повторного размещения на одном потоке.

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

18

На основе предложения Adamski's test-and-set вы также должны ознакомиться с концепцией «быстрых мьютексов пользовательского пространства» или futexes.

Futexes обладают желательным свойством, чтобы они не требовали системного вызова ядра в обычных случаях блокировки или разблокировки uncontended мьютекса. В этих случаях код пользовательского режима успешно использует операцию атома compare and swap (CAS) для блокировки или разблокировки мьютекса.

Если CAS терпит неудачу, мьютекс разрешен, а системный вызов ядра - sys_futex под Linux - должен использоваться либо для ожидания мьютекса (в случае блокировки), либо для пробуждения других потоков (в случае разблокировки) ,

Если вы серьезно относитесь к его реализации, убедитесь, что вы также прочитали paper Ульриха Дреппера.

Смежные вопросы