Compartilhar via


Bloqueios de rotação na fila

** Os bloqueios de espera em fila são uma variante de bloqueios de rotação que funcionam bem para bloqueios com alta contenção. Os spin locks tradicionais e sem fila são uma opção melhor para bloqueios com baixa contenção ou de curta duração.

Os benefícios de usar um spin lock 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, à medida que fazem loop contínuo (ou "spin") verificando o status do bloqueio. Isso pode prejudicar o desempenho do sistema, especialmente em sistemas multiprocessadores. Os bloqueios de rotação na fila reduzem isso organizando threads em uma fila. Quando um thread adquire um bloqueio, somente o próximo na linha está girando ativamente, aguardando para adquirir o bloqueio. Isso reduz os ciclos de CPU desperdiçados ao girar, especialmente quando o bloqueio é mantido por durações mais longas.

  2. Imparcialidade e evasão da fome: um dos problemas com bloqueios básicos de rotação é a falta de justiça; um thread pode passar fome e nunca adquirir o bloqueio se outros threads estiverem adquirindo e liberando-o continuamente. Os bloqueios de rotação enfileirados resolvem isso garantindo que os threads adquiram o bloqueio na ordem em que tentaram. Esse tratamento 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 essencial para o desempenho. Os bloqueios de rotação enfileirados são mais escalonáveis do que os bloqueios de rotação tradicionais porque reduzem a sobrecarga nos processadores minimizando a rotação ativa em todos os núcleos. Isso é particularmente importante em sistemas multi-núcleos de alto desempenho, em que a eficiência do driver pode afetar diretamente o desempenho geral do sistema.

  4. Uso eficiente de recursos do sistema: ao reduzir a rotação desnecessária do processador, os bloqueios de rotação enfileirados permitem que o sistema use seus recursos com mais eficiência. Isso não só melhora o desempenho do driver do 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 enfileirados abstraem a complexidade para longe do desenvolvedor. Eles fornecem um mecanismo simples e confiável para proteger os 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 de bloqueios, melhorando assim a confiabilidade do driver.

Abaixo está um trecho de código simplificado que demonstra as operações descritas com um spin lock enfileirado 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 passa por ponteiro para KeAcquireInStackQueuedSpinLock. O driver passa a mesma estrutura por ponteiro para KeReleaseInStackQueuedSpinLock quando libera o bloqueio de rotação.

Normalmente, os drivers devem alocar a estrutura na pilha sempre que adquirirem o bloqueio. Um driver não deve alocar a estrutura como parte do contexto de seu dispositivo e, em seguida, compartilhar essa mesma estrutura entre múltiplos threads.

Os drivers não devem misturar chamadas às rotinas de bloqueio de rotação enfileiradas e às rotinas comuns do SpinLock KeXxx no mesmo bloqueio de rotação.

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