Compartilhar via


Mutexes rápidos e Mutexes protegidos

A partir do Windows 2000, os drivers podem usar mutexes rápidos se exigirem uma forma de exclusão mútua com baixa sobrecarga para códigos que são executados em IRQL <= APC_LEVEL. Um mutex rápido pode proteger um trecho de código que deve ser acessado por apenas um thread de cada vez. Para entrar no caminho do código protegido, o thread adquire o mutex. Se outro thread já tiver adquirido o mutex, a execução do thread atual será suspensa até que o mutex seja liberado. Para sair do caminho de código protegido, o thread libera o mutex.

A partir do Windows Server 2003, os drivers também podem usar mutexes protegidos. Os mutexes protegidos são substituições diretas para mutexes rápidos, mas fornecem melhor desempenho. Como um mutex rápido, um mutex protegido pode proteger um caminho de código que deve ser acessado por apenas um thread de cada vez. No entanto, o código que usa mutexes protegidos é executado mais rapidamente do que o código que usa mutexes rápidos.

Em versões do Windows antes do Windows 8, os mutexes protegidos são implementados de forma diferente dos mutexes rápidos. Um caminho de código protegido por um mutex rápido é executado em IRQL = APC_LEVEL. Um caminho de código protegido por um mutex protegido é executado em IRQL <= APC_LEVEL mas com todas as APCs desabilitadas. Nessas versões anteriores do Windows, a aquisição de um mutex protegido é uma operação mais rápida do que a aquisição de um mutex rápido. No entanto, esses dois tipos de mutex se comportam de forma idêntica e estão sujeitos às mesmas restrições. Em particular, rotinas do kernel que são ilegais de serem chamadas em IRQL = APC_LEVEL não devem ser chamadas de um caminho de execução protegido por um mutex rápido ou um mutex protegido.

A partir do Windows 8, os mutexes protegidos são implementados como mutexes rápidos. Em um caminho de código protegido por um mutex guardado ou um mutex rápido, o Verificador de Driver trata chamadas para rotinas de kernel como ocorrendo em IRQL = APC_LEVEL. Como nas versões anteriores do Windows, chamadas que são ilegais em APC_LEVEL também são ilegais em um caminho de código que é protegido por um mutex guardado ou um mutex rápido.

Mutexes rápidos

Um mutex rápido é representado por uma estrutura FAST_MUTEX . O driver aloca seu próprio armazenamento para uma estrutura de FAST_MUTEX e, em seguida, chama a rotina ExInitializeFastMutex para inicializar a estrutura.

Um thread adquire um mutex rápido fazendo um dos seguintes procedimentos:

  • Chamando a rotina ExAcquireFastMutex . Se o mutex já tiver sido adquirido por outro thread, a execução do thread de chamada será suspensa até que o mutex fique disponível.

  • Chamando a rotina ExTryToAcquireFastMutex para tentar adquirir o mutex rápido sem suspender o thread atual. A rotina retorna imediatamente, independentemente de o mutex ter sido adquirido. ExTryToAcquireFastMutex retornará TRUE se tiver adquirido com êxito o mutex para o chamador; caso contrário, ele retornará FALSE.

Um thread chama ExReleaseFastMutex para lançar um mutex rápido que foi adquirido por ExAcquireFastMutex ou ExTryToAcquireFastMutex.

Um caminho de código protegido por um mutex rápido é executado em IRQL = APC_LEVEL. ExAcquireFastMutex e ExTryToAcquireFastMutex geram o IRQL atual para APC_LEVEL e ExReleaseFastMutex restaura o IRQL original. Assim, todas as APCs são desabilitadas enquanto o thread contém um mutex rápido.

Se for garantido que um caminho de código seja sempre executado em APC_LEVEL, o driver poderá chamar ExAcquireFastMutexUnsafe e ExReleaseFastMutexUnsafe para aquisição e liberação de um mutex rápido. Essas rotinas não alteram o IRQL atual e só podem ser usadas com segurança quando o IRQL atual é APC_LEVEL.

Mutexes rápidos não podem ser adquiridos recursivamente. Se um thread que já está mantendo um mutex rápido tentar adquiri-lo novamente, esse thread entrará em deadlock. Mutexes rápidos só podem ser usados no código que é executado em IRQL <= APC_LEVEL.

Mutexes protegidos

Os mutexes protegidos, que estão disponíveis a partir do Windows Server 2003, executam a mesma função que os mutexes rápidos, mas com desempenho mais alto.

A partir do Windows 8, mutexes protegidos e mutexes rápidos são implementados de forma idêntica.

Em versões do Windows antes do Windows 8, os mutexes protegidos são implementados de forma diferente dos mutexes rápidos. A aquisição de um mutex rápido eleva o IRQL atual para APC_LEVEL, enquanto a aquisição de um mutex protegido entra em uma região protegida, que é uma operação mais rápida. Para obter mais informações sobre regiões protegidas, consulte Regiões Críticas e Regiões Protegidas.

Um mutex protegido é representado por uma estrutura KGUARDED_MUTEX. O driver aloca seu próprio armazenamento para uma estrutura KGUARDED_MUTEX e, em seguida, chama a rotina KeInitializeGuardedMutex para inicializar a estrutura.

Um thread adquire um mutex protegido fazendo um dos seguintes procedimentos:

  • Chamando KeAcquireGuardedMutex. Se o mutex já tiver sido adquirido por outro thread, a execução do thread de chamada será suspensa até que o mutex fique disponível.

  • Chamando KeTryToAcquireGuardedMutex para tentar adquirir o mutex protegido sem suspender o thread atual. A rotina retorna imediatamente, independentemente de o mutex ter sido adquirido. KeTryToAcquireGuardedMutex retorna TRUE se adquirir com êxito o mutex para o chamador; caso contrário, ele retorna FALSE.

Um thread chama KeReleaseGuardedMutex para liberar um mutex protegido que foi adquirido por KeAcquireGuardedMutex ou KeTryToAcquireGuardedMutex.

Um thread que contém um mutex protegido é executado implicitamente dentro de uma região protegida. KeAcquireGuardedMutex e KeTryToAcquireGuardedMutex entram na região protegida, enquanto KeReleaseGuardedMutex sai dela. Todas as APCs são desabilitadas enquanto o thread contém um mutex protegido.

Se for garantido que um caminho de código seja executado com todas as APCs desabilitadas, o driver poderá usar KeAcquireGuardedMutexUnsafe e KeReleaseGuardedMutexUnsafe para adquirir e liberar o mutex protegido. Essas rotinas não entram ou saem de uma região protegida e só podem ser usadas dentro de uma região protegida já existente ou em IRQL = APC_LEVEL.

Mutexes protegidos não podem ser adquiridos recursivamente. Se uma thread que já está segurando um mutex protegido tentar adquiri-lo, essa thread entrará em deadlock. Os mutexes protegidos só podem ser usados no código executado em IRQL <= APC_LEVEL.