Поскольку Вы определили g (), чтобы быть виртуальными, наиболее полученный g () будет искаться в vtable из класса и звонил независимо от типа, Ваш код в настоящее время получает доступ к нему.
Посмотрите FAQ C++ на виртуальных функциях .
Ознакомьтесь с описанием машинной инструкции Test-and-set в Википедии, в которой упоминается, как атомарные операции выполняются на машинном уровне. Я могу представить, что большинство реализаций мьютексов на уровне языка полагаются на поддержку машинного уровня, такую как Test-and-set.
Мьютекс предпочтительно запускается в ядре операционной системы, сохраняя при этом как можно меньший объем кода, чтобы избежать отключения при выполнении задачи. -переключение на другой процесс. Поэтому точная реализация немного секрет. Хотя это не сложно. По сути, это объект с логическим полем, которое он получает и устанавливает.
Вокруг базовой логики мьютекса есть обертки, которые оборачивают его в объект ... Затем еще несколько объектов обертки, чтобы сделать его доступным вне ядра. А затем еще одна оболочка, чтобы сделать ее доступной в .NET. А затем несколько программистов напишут свой собственный код оболочки для всего этого для своих логических нужд. Обертки вокруг оболочек действительно делают их темной территорией.
Теперь, имея эти базовые знания о внутреннем устройстве мьютексов, все, что я надеюсь, - это то, что вы собираетесь использовать одну реализацию, которая полагается на ядро и находящееся ниже оборудование. Это были бы самые надежные. (Если оборудование поддерживает их.) Если мьютекс, который вы используете, не работает на этом уровне ядра / оборудования, он все еще может быть надежным, но я бы посоветовал не использовать его, если нет альтернативы.
Как насколько мне известно, Windows, Linux и. Все NET будут использовать мьютексы на уровне ядра / оборудования.
Страница Википедии, на которую я указал, объясняет больше о внутренней логике и возможных реализациях. Предпочтительно, чтобы мьютекс управлялся аппаратным обеспечением, таким образом, делая все получение / настройку мьютекса неделимым этапом . (Просто чтобы убедиться, что система не переключает задачи между ними.)
Interlocked.CompareExchange
достаточно для реализации спин-блокировок. Однако это довольно сложно сделать правильно. См. блог Джо Даффи для примера задействованных тонкостей.
Я использовал Reflector.NET для декомпиляции исходного кода для System.Threading.ReaderWriterLockSlim
, который был добавлен в последнюю версию .NET framework.
В основном это было использует Interlocked.CompareExchange
, Thread.SpinWait
и Thread.Sleep
для достижения синхронизации. Есть несколько экземпляров EventWaitHandle
(объект ядра), которые используются при некоторых обстоятельствах.
Также добавлена некоторая сложность для поддержки повторного входа в одном потоке.
Если вас интересует эта область и работая в .NET (или, по крайней мере, можете прочитать его), вам может быть интересно проверить этот класс.
Основываясь на предложении Адамски test-and-set
, вам также следует взглянуть на концепция «быстрых мьютексов в пользовательском пространстве» или фьютексов .
Фьютексы обладают желаемым свойством, заключающимся в том, что они не требуют системного вызова ядра в общих случаях блокировки или разблокировки неконтролируемого мьютекс. В этих случаях код пользовательского режима успешно использует атомарную операцию сравнения и обмена (CAS) для блокировки или разблокировки мьютекса.
Если CAS терпит неудачу, мьютекс будет оспорен, а системный вызов ядра - - sys_futex
под Linux - необходимо использовать либо для ожидания мьютекса (в случае блокировки), либо для пробуждения других потоков (в случае разблокировки).
Если вы серьезно относитесь к реализации этого сами,