Bloqueios de rotação em fila

As travas de rotação em fila são uma variante das travas de rotação que funcionam bem para bloqueios altamente disputados. As travas giratórias tradicionais e sem fila são uma escolha melhor para bloqueios levemente disputados ou de duração mais curta.

Os benefícios de usar um bloqueio de rotação em fila incluem:

  1. Contenção reduzida do processador: Os bloqueios de rotação tradicionais podem levar a uma contenção significativa do processador quando vários threads tentam adquirir o bloqueio simultaneamente, pois eles continuamente fazem loop (ou "spin") verificando o status do bloqueio. Isso pode degradar o desempenho do sistema, especialmente em sistemas com vários processadores. Os bloqueios de rotação em fila atenuam isso organizando threads em uma fila. Quando uma rosca adquire uma trava, apenas a próxima na fila está girando ativamente, esperando para adquirir a fechadura. Isso reduz os ciclos de CPU desperdiçados ao girar, especialmente quando o bloqueio é mantido por durações mais longas.

  2. Equidade e evitar a fome: Um dos problemas com fechaduras de giro básicas é a falta de justiça, um fio pode passar fome e nunca adquirir o bloqueio se outros fios estiverem continuamente adquirindo e liberando-o. Os bloqueios de rotação em fila resolvem isso garantindo que os threads adquiram o bloqueio na ordem em que tentaram. Esse manuseio sequencial evita a fome e garante que todos os threads sejam atendidos ao longo do tempo.

  3. Escalabilidade: À medida que o número de processadores ou núcleos aumenta em um sistema, a eficiência dos mecanismos de sincronização torna-se crítica para o desempenho. Os bloqueios de rotação em fila são mais escaláveis do que os bloqueios de rotação tradicionais porque reduzem a sobrecarga dos processadores, minimizando a rotação ativa em todos os núcleos. Isso é particularmente importante em sistemas multi-core de alto desempenho, onde a eficiência do driver pode afetar diretamente o desempenho geral do sistema.

  4. Uso eficiente dos recursos do sistema: Ao reduzir a rotação desnecessária do processador, os bloqueios de rotação em fila permitem que o sistema use seus recursos de forma mais eficiente. Isso não apenas melhora o desempenho do driver de dispositivo, mas também tem um impacto positivo na capacidade de resposta geral do sistema e no consumo de energia, o que é especialmente benéfico em ambientes sensíveis à energia.

  5. Simplicidade e confiabilidade: Apesar de suas vantagens em reduzir a contenção e melhorar a justiça, os bloqueios de rotação em fila abstraem a complexidade do desenvolvedor. Eles fornecem um mecanismo simples e confiável para proteger recursos compartilhados sem que o desenvolvedor precise implementar uma lógica de bloqueio complexa. Essa simplicidade reduz a probabilidade de bugs relacionados ao manuseio inadequado do bloqueio, aumentando assim a confiabilidade do motorista.

Abaixo está um trecho de código simplificado demonstrando as operações descritas com um bloqueio de rotação em fila em um driver do Modo Kernel do Windows. Este exemplo mostra como declarar e inicializar um bloqueio de rotação usando KeInitializeSpinLock e, em seguida, adquirir e liberar o bloqueio usando KeAcquireInStackQueuedSpinLock e KeReleaseInStackQueuedSpinLock, respectivamente.

KSPIN_LOCK SpinLock;  
KLOCK_QUEUE_HANDLE LockHandle;  

// Initialize the spin lock  
KeInitializeSpinLock(&SpinLock);  

// Assume this function is called in some kind of context where   
// the below operations make sense, e.g., in a device I/O path  

// Acquire the queued spin lock  
KeAcquireInStackQueuedSpinLock(&SpinLock, &LockHandle);  

// At this point, the current thread holds the spin lock.  
// Perform thread-safe operations here.  
    
// ...  

// Release the queued spin lock  
KeReleaseInStackQueuedSpinLock(&LockHandle);  

O driver aloca uma estrutura KLOCK_QUEUE_HANDLE que ele passa pelo ponteiro para KeAcquireInStackQueuedSpinLock. O driver passa a mesma estrutura por ponteiro para KeReleaseInStackQueuedSpinLock quando ele libera o bloqueio de rotação.

Normalmente, os motoristas devem alocar a estrutura na pilha cada vez que adquirirem o bloqueio. Um driver não deve alocar a estrutura como parte de seu contexto de dispositivo e, em seguida, compartilhar a mesma estrutura de vários threads.

Os motoristas não devem misturar chamadas para as rotinas de bloqueio de rotação em fila e as rotinas comuns de KeXxxSpinLock no mesmo bloqueio de rotação.

Se o driver já estiver em IRQL = DISPATCH_LEVEL, ele poderá chamar KeAcquireInStackQueuedSpinLockAtDpcLevel e KeReleaseInStackQueuedSpinLockFromDpcLevel em vez disso.