Быстрые мьютексы и защищенные мьютексы

Начиная с Windows 2000, драйверы могут использовать быстрые мьютексы , если им требуется форма взаимного исключения с низкими затратами для кода, который выполняется в IRQL <= APC_LEVEL. Быстрый мьютекс может защитить путь кода, который должен вводиться только одним потоком за раз. Чтобы ввести путь к защищенному коду, поток получает мьютекс. Если другой поток уже получил мьютекс, выполнение текущего потока приостанавливается до освобождения мьютекса. Чтобы выйти из защищенного пути кода, поток освобождает мьютекс.

Начиная с Windows Server 2003, драйверы также могут использовать защищенные мьютексы. Защищенные мьютексы являются заменой быстрых мьютексов, но обеспечивают лучшую производительность. Как и быстрый мьютекс, защищенный мьютекс может защитить путь кода, который должен быть введен только одним потоком за раз. Однако код, использующий защищенные мьютексы, выполняется быстрее, чем код, использующий быстрые мьютексы.

В версиях Windows до Windows 8 защищенные мьютексы реализуются иначе, чем быстрые мьютексы. Путь кода, защищенный быстрым мьютексом, выполняется в IRQL = APC_LEVEL. Путь к коду, защищенный защищенным мьютексом, выполняется в IRQL <= APC_LEVEL но со всеми БПП отключены. В этих более ранних версиях Windows приобретение защищенного мьютекса выполняется быстрее, чем приобретение быстрого мьютекса. Однако эти два типа мьютексов ведут себя одинаково и распространяются на одни и те же ограничения. В частности, подпрограммы ядра, которые недопустимы для вызова в IRQL = APC_LEVEL, не должны вызываться из пути кода, защищенного либо быстрым мьютексом, либо защищенным мьютексом.

Начиная с Windows 8, защищенные мьютексы реализуются как быстрые мьютексы. В пути кода, защищенном защищенным мьютексом или быстрым мьютексом, средство проверки драйверов обрабатывает вызовы подпрограмм ядра как выполняемые в IRQL = APC_LEVEL. Как и в более ранних версиях Windows, вызовы, которые являются незаконными в APC_LEVEL, являются незаконными в пути кода, защищенном мьютексом или быстрым мьютексом.

Быстрые мьютексы

Быстрый мьютекс представлен структурой FAST_MUTEX . Драйвер выделяет собственное хранилище для структуры FAST_MUTEX , а затем вызывает подпрограмму ExInitializeFastMutex для инициализации структуры.

Поток получает быстрый мьютекс, выполнив одно из следующих действий:

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

  • Вызов подпрограммы ExTryToAcquireFastMutex для получения быстрого мьютекса без приостановки текущего потока. Подпрограмма возвращается немедленно, независимо от того, был ли приобретен мьютекс. ExTryToAcquireFastMutex возвращает значение TRUE , если он успешно получил мьютекс для вызывающего объекта; В противном случае возвращается значение FALSE.

Поток вызывает ExReleaseFastMutex для освобождения быстрого мьютекса, приобретенного ExAcquireFastMutex или ExTryToAcquireFastMutex.

Путь кода, защищенный быстрым мьютексом, выполняется в IRQL = APC_LEVEL. ExAcquireFastMutex и ExTryToAcquireFastMutex повышают текущий irQL до APC_LEVEL, а ExReleaseFastMutex восстанавливает исходный IRQL. Таким образом, все APC отключены, а поток содержит быстрый мьютекс.

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

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

Защищенные мьютексы

Защищенные мьютексы, доступные начиная с Windows Server 2003, выполняют ту же функцию, что и быстрые мьютексы, но с более высокой производительностью.

Начиная с Windows 8, защищенные мьютексы и быстрые мьютексы реализуются одинаково.

В версиях Windows до Windows 8 защищенные мьютексы реализуются иначе, чем быстрые мьютексы. Получение быстрого мьютекса приводит к APC_LEVEL текущего IRQL, а получение защищенного мьютекса входит в защищенную область, что является более быстрой операцией. Дополнительные сведения о защищенных регионах см. в разделах Критические регионы и Защищенные регионы.

Защищенный мьютекс представлен структурой KGUARDED_MUTEX . Драйвер выделяет собственное хранилище для структуры KGUARDED_MUTEX , а затем вызывает подпрограмму KeInitializeGuardedMutex для инициализации структуры.

Поток получает защищенный мьютекс, выполнив одно из следующих действий:

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

  • Вызов метода KeTryToAcquireGuardedMutex для получения защищенного мьютекса без приостановки текущего потока. Подпрограмма возвращается немедленно, независимо от того, был ли приобретен мьютекс. KeTryToAcquireGuardedMutex возвращает значение TRUE , если он успешно получил мьютекс для вызывающего объекта; В противном случае возвращается значение FALSE.

Поток вызывает KeReleaseGuardedMutex для освобождения защищенного мьютекса, приобретенного keAcquireGuardedMutex или KeTryToAcquireGuardedMutex.

Поток, содержащий защищенный мьютекс, неявно выполняется внутри защищенной области. KeAcquireGuardedMutex и KeTryToAcquireGuardedMutex входят в защищенную область, а KeReleaseGuardedMutex выходит из него. Все APC отключены, а поток содержит защищенный мьютекс.

Если путь кода гарантированно будет выполняться со всеми APC отключены, драйвер может вместо этого использовать KeAcquireGuardedMutexUnsafe и KeReleaseGuardedMutexUnsafe для получения и освобождения защищенного мьютекса. Эти подпрограммы не входят в защищенный регион и не выходят из нее. Их можно использовать только в уже существующем защищенном регионе или в IRQL = APC_LEVEL.

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