Partager via


Verrous tournants en file d'attente

Les verrous de rotation en file d'attente sont une variante des verrous de rotation qui fonctionnent bien pour les verrous très disputés. Les verrous de rotation traditionnels et non mis en file d'attente sont un meilleur choix pour les verrous faiblement disputés ou de courte durée.

Les avantages de l’utilisation d’un verrou de rotation en file d’attente sont les suivants :

  1. Contention réduite du processeur : les verrous de rotation traditionnels peuvent entraîner une contention significative du processeur lorsque plusieurs threads tentent d’acquérir le verrou simultanément, car ils effectuent une boucle continue (ou « spin ») en vérifiant l’état du verrou. Cela peut dégrader les performances du système, en particulier sur les systèmes multiprocesseurs. Les verrous de rotation mis en file d’attente atténuent ce problème en organisant des threads dans une file d’attente. Lorsqu’un thread acquiert un verrou, seul le suivant en ligne tourne activement, en attendant d’acquérir le verrou. Cela réduit les cycles d'UC gaspillés en attente active, en particulier lorsque le verrou est maintenu pendant des durées plus longues.

  2. L’équité et l’évitement de la faim : l’un des problèmes liés aux verrous de rotation de base est le manque d’équité ; un thread peut être affamé et ne jamais acquérir le verrou si d’autres threads l’acquiert et le libèrent en continu. Les verrous de rotation mis en file d’attente résolvent ce problème en s'assurant que les threads obtiennent le verrou dans l'ordre de leur tentative. Cette gestion séquentielle empêche la faim et garantit que tous les threads sont pris en charge au fil du temps.

  3. Scalabilité : à mesure que le nombre de processeurs ou de cœurs augmente dans un système, l’efficacité des mécanismes de synchronisation devient essentielle pour les performances. Les verrous de rotation mis en file d’attente sont plus évolutifs que les verrous de rotation traditionnels, car ils réduisent la surcharge sur les processeurs en réduisant la rotation active sur tous les cœurs. Cela est particulièrement important dans les systèmes multicœurs hautes performances, où l’efficacité du pilote peut avoir un impact direct sur les performances globales du système.

  4. Utilisation efficace des ressources système : en réduisant l’épinglage inutile du processeur, les verrous de rotation mis en file d’attente permettent au système d’utiliser ses ressources plus efficacement. Cela améliore non seulement les performances du pilote de périphérique, mais a également un impact positif sur la réactivité globale et la consommation d’énergie du système, qui est particulièrement bénéfique dans les environnements sensibles à l’alimentation.

  5. Simplicité et fiabilité : malgré leurs avantages en réduisant la contention et en améliorant l’équité, les verrous de rotation mis en file d’attente masquent la complexité pour le développeur. Ils fournissent un mécanisme simple et fiable pour protéger les ressources partagées sans que le développeur ait à implémenter une logique de verrouillage complexe. Cette simplicité réduit la probabilité de bogues liés à la gestion incorrecte des verrous, améliorant ainsi la fiabilité du pilote.

Vous trouverez ci-dessous un extrait de code simplifié illustrant les opérations décrites avec un verrou de rotation en file d’attente dans un pilote en mode noyau Windows. Cet exemple montre comment déclarer et initialiser un verrou de spin à l’aide de KeInitializeSpinLock, puis acquérir et libérer le verrou à l’aide de KeAcquireInStackQueuedSpinLock et KeReleaseInStackQueuedSpinLock, respectivement.

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);  

Le pilote alloue une structure KLOCK_QUEUE_HANDLE qu'il passe par pointeur à KeAcquireInStackQueuedSpinLock. Le pilote passe la même structure par pointeur vers KeReleaseInStackQueuedSpinLock lorsqu’il libère le verrou de rotation.

Les pilotes doivent normalement allouer la structure sur la pile chaque fois qu’ils obtiennent le verrou. Un pilote ne doit pas allouer la structure dans son contexte de périphérique, puis partager la même structure entre plusieurs threads.

Les pilotes ne doivent pas mélanger les appels aux routines de verrou tournant en file d’attente et les routines KeXxxSpinLock ordinaires sur le même verrou tournant.

Si le pilote est déjà à IRQL = DISPATCH_LEVEL, il peut appeler KeAcquireInStackQueuedSpinLockAtDpcLevel et KeReleaseInStackQueuedSpinLockFromDpcLevel plutôt.