Comme la question l'implique en disant que les verrous d'attente sont un "gaspillage", les verrous d'attente ne doivent être maintenus que brièvement.
Les verrous tournants ne sont pas le seul moyen de synchroniser plusieurs threads. Les mutex/sémaphores sont également utilisés dans le noyau Linux, tout comme d'autres primitives de synchronisation (par exemple, les files d'attente, les événements).
Cependant, le noyau doit gérer des cas que l'espace utilisateur ne voit jamais, un cas courant étant les gestionnaires d'interruptions. Les gestionnaires d'interruption ne peuvent pas être replanifiés sous Linux, mais doivent souvent utiliser une primitive de synchronisation (par exemple, pour ajouter un élément de travail à une liste chaînée qu'un autre thread traitera plus avant). Étant donné que les gestionnaires d'interruptions ne peuvent pas dormir, ils ne peuvent pas utiliser les mutex, les files d'attente, etc. Cela laisse à peu près les verrous tournants. Si un thread doit synchroniser l'accès avec un gestionnaire d'interruption, il doit également utiliser le même verrou tournant.
Les spinlocks ne sont pas nécessairement un gaspillage. Ils sont optimisés pour le cas de non-contention/non-attente et peuvent être pris et libérés très rapidement. Dans ce cas, elles sont plus rapides et impliquent moins de surcharge que les autres primitives de synchronisation.
Le choix entre un spinlock et une autre construction qui amène l'appelant à bloquer et à abandonner le contrôle d'un processeur est dans une large mesure régi par le temps nécessaire pour effectuer un changement de contexte (sauvegarder les registres/état dans le thread de verrouillage et restaurer les registres/état dans un autre fil). Le temps que cela prend et le coût du cache pour le faire peuvent être importants.
Si un verrou tournant est utilisé pour protéger l'accès aux registres matériels ou similaires où tout autre thread qui accède ne prendra que quelques millisecondes ou moins avant de libérer le verrou, alors c'est une bien meilleure utilisation du temps du processeur pour tourner en attente plutôt que de changer de contexte et de continuer.
D'autres ont répondu. Je vais résumer les cas où vous utiliseriez le spinlock et les règles d'utilisation du spinlock.
1. Quand le spinlock est utilisé ?
Rép :dans les situations suivantes.
- Le thread qui détient le verrou n'est pas autorisé à dormir.
- Le thread qui attend un verrou ne dort pas, mais tourne en boucle serrée.
Lorsqu'il est correctement utilisé, le verrou tournant peut offrir des performances supérieures à celles du sémaphore.Ex :gestionnaire d'interruption.
2. Quelles sont les règles d'utilisation des spinlocks ?
Réponse :
Règle - 1 :tout code qui contient le verrou tournant ne peut pas abandonner le processeur pour quelque raison que ce soit, sauf pour entretenir des interruptions (parfois même pas alors). Ainsi, le code contenant le spinlock ne peut pas dormir.
Raison :supposons que votre conducteur tenant un verrou tournant s'endorme. Ex :appelle la fonction copy_from_user()
ou copy_to_user()
, ou la préemption du noyau démarre, de sorte que le processus de priorité plus élevée a mis votre code de côté. Effectivement, le processus abandonne le CPU tenant le verrou tournant.
Maintenant, nous ne savons pas quand le code libérera le verrou. Si un autre thread essaie d'obtenir le même verrou, il tournera très longtemps. Dans le pire des cas, cela entraînerait un blocage.
Le cas de préemption du noyau est géré par le code spinlock lui-même. Chaque fois que le code du noyau contient un verrou tournant, la préemption est désactivée sur le processeur concerné. Même le système monoprocesseur doit désactiver la préemption de cette manière.
Règle - 2 :désactivez les interruptions sur le processeur local pendant que le verrou tournant est maintenu.
Raison :Aidez votre pilote à prendre un spinlock qui contrôle l'accès à l'appareil, puis émet une interruption. Cela provoque l'exécution du gestionnaire d'interruption. Maintenant, le gestionnaire d'interruption a également besoin du verrou pour accéder au périphérique. Si le gestionnaire d'interruptions s'exécute sur le même processeur, il commencera à tourner. Le code du conducteur ne peut pas non plus s'exécuter pour libérer le verrou. Ainsi, le processeur tournera pour toujours.
Règle - 3 : les Spinlocks doivent être maintenus le moins de temps possible.
Raison :les longs temps de maintien des verrous empêchent également le processeur actuel de planifier, ce qui signifie qu'un processus de priorité plus élevée peut devoir attendre pour obtenir le processeur.
Cela a donc un impact sur la latence du noyau (le temps qu'un processus peut devoir attendre pour être planifié). En règle générale, les verrous tournants doivent être maintenus pendant la durée, inférieure à ce que le processeur prend pour effectuer un changement de contexte entre les threads.