Подтвердить что ты не робот

Как реализованы мьютексы?

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

4b9b3361

Ответ 1

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

Ответ 2

Основываясь на предложении Адамски о test-and-set, вы также должны взглянуть на концепцию "быстрых мьютексов пространства пользователя" или фьютексов.

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

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

Если вы серьезно относитесь к реализации этого самостоятельно, убедитесь, что вы также читали Ulrich Drepper бумагу.

Ответ 3

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

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

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

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

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

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

Ответ 4

Interlocked.CompareExchange достаточно для реализации spindlock. Хотя это довольно сложно сделать правильно. См. Блог Джо Даффи для примера вовлеченных тонкостей.

Ответ 5

Немного сборки, чтобы продемонстрировать блокировку атомарно:

; BL is the mutex id
; shared_val, a memory address

CMP [shared_val],BL ; Perhaps it is locked to us anyway
JZ .OutLoop2
.Loop1:
CMP [shared_val],0xFF ; Free
JZ .OutLoop1 ; Yes
pause ; equal to rep nop.
JMP .Loop1 ; Else, retry

.OutLoop1:

; Lock is free, grab it
MOV AL,0xFF
LOCK CMPXCHG [shared_val],BL
JNZ .Loop1 ; Write failed

.OutLoop2: ; Lock Acquired

Ответ 6

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

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

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

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