Que sont exactement les «verrous tournants»?

108

Je me suis toujours demandé ce qu'ils étaient: à chaque fois que j'entends parler d'eux, des images d'appareils futuristes ressemblant à des volants d'inertie vont danser (rouler?) Dans mon esprit ...

Que sont-ils?

RCIX
la source

Réponses:

125

Lorsque vous utilisez des verrous normaux (mutex, sections critiques, etc.), le système d'exploitation met votre thread dans l'état WAIT et le préempte en planifiant d'autres threads sur le même noyau. Cela a une pénalité de performances si le temps d'attente est vraiment court, car votre thread doit maintenant attendre une préemption pour recevoir à nouveau le temps CPU.

En outre, les objets du noyau ne sont pas disponibles dans tous les états du noyau, comme dans un gestionnaire d'interruption ou lorsque la pagination n'est pas disponible, etc.

Les Spinlocks ne provoquent pas de préemption mais attendent en boucle ("spin") jusqu'à ce que l'autre noyau libère le verrou. Cela empêche le thread de perdre son quantum et continue dès que le verrou est libéré. Le mécanisme simple des verrous rotatifs permet à un noyau de l'utiliser dans presque tous les états.

C'est pourquoi sur une machine à un seul cœur, un verrou tournant est simplement un "désactiver les interruptions" ou "augmenter l'IRQL" qui empêche complètement la planification des threads.

Les Spinlocks permettent en fin de compte aux noyaux d'éviter les «Big Kernel Lock» (un verrou acquis lorsque le noyau entre dans le noyau et libéré à la sortie) et ont un verrouillage granulaire sur les primitives du noyau, entraînant un meilleur multi-traitement sur les machines multi-cœurs donc de meilleures performances.

EDIT : Une question s'est posée: "Cela signifie-t-il que je devrais utiliser des verrous rotatifs dans la mesure du possible?" et j'essaierai d'y répondre:

Comme je l'ai mentionné, les Spinlocks ne sont utiles que dans les endroits où le temps d'attente anticipé est plus court qu'un quantum (lire: millisecondes) et la préemption n'a pas beaucoup de sens (par exemple, les objets du noyau ne sont pas disponibles).

Si le temps d'attente est inconnu ou si vous êtes en mode utilisateur, les Spinlocks ne sont pas efficaces. Vous consommez 100% du temps CPU sur le cœur en attente tout en vérifiant si un verrou tournant est disponible. Vous empêchez d'autres threads de s'exécuter sur ce noyau jusqu'à ce que votre quantum expire. Ce scénario n'est réalisable que pour de courtes rafales au niveau du noyau et peu probable une option pour une application en mode utilisateur.

Voici une question sur SO abordant cela: Spinlocks, quelle est leur utilité?

Sedat Kapanoglu
la source
cela signifie-t-il que je devrais tourner les verrous (au lieu du mutex, de la section critique, etc.) dans la mesure du possible?
1
quelqu'un, s'il vous plaît, corrigez-moi si je me trompe, mais un verrou tournant ne désactive pas la préemption (c'est-à-dire la reprogrammation). pour la simple raison que, si le verrou tournant attend une ressource verrouillée par un autre processus, alors ce second processus doit avoir une chance de s'exécuter et de libérer la ressource. ou, l'exécution du deuxième processus nécessite la préemption du premier processus (rotation).
user1284631
ce que fait spinlock à la place, c'est qu'il ne change pas l'état du processus de TASK_RUNNING en TASK_INTERRUPTIBLE (qui est un état de veille) et, par conséquent, il ne sauvegarde pas tout ce qui concerne ce processus (mémoire, cache, etc.). au lieu de cela, le processus de rotation est préempté, mais il ne quitte jamais les processus "immédiatement programmables": il est conservé en mémoire et les autres processus sont régulièrement exécutés jusqu'à ce que l'un d'eux libère la ressource que le spinner attend: à ce moment-là, le spinlock revient simplement et le processus de rotation peut continuer. il attend dans un état toujours TASK_RUNNING.
user1284631
1
vous avez raison à ce sujet (voir aussi ceci: linuxjournal.com/article/5833 ), mais le fait est que le verrouillage d'une ressource et la désactivation des interruptions, bien qu'utiles à effectuer conjointement, sont par ailleurs des concepts indépendants. vous voulez essentiellement vous assurer que vous n'utilisez pas une ressource trouvée dans un état incohérent, et c'est pourquoi vous testez son verrouillage. la désactivation des interruptions (également la préemption) garantit que oui, personne ne gâchera votre resurce pendant que vous y faites face. mais, pour cela, il faut être sûr que la ressource est gratuite lors de son acquisition.
user1284631
1
(puis désactivez les interruptions juste pour être sûr qu'aucune autre tâche ne vous empêche de jouer avec la ressource). sur UP (uni-processor), c'est toujours le cas: le tout premier spinlock (et les suivants) est simplement accordé, les interruptions (ie préemption) sont désactivées, et la tâche utilisant la ressource n'est jamais préemptée: elle fait tout son travail avec la ressource, puis activer les interruptions (et donc la préemption). lorsque la préemption est activée, la ressource est déjà gratuite. fondamentalement, sur UP, il n'y a pas de conflit de spinlock et il n'y a pas d'attente . sur SMP ça pourrait être.
user1284631
25

Supposons qu'une ressource est protégée par un verrou, un thread qui souhaite accéder à la ressource doit d'abord acquérir le verrou. Si le verrou n'est pas disponible, le thread peut vérifier à plusieurs reprises si le verrou a été libéré. Pendant ce temps, le thread occupé attend, vérifiant le verrou, utilisant le processeur, mais ne faisant aucun travail utile. Un tel verrou est appelé verrou tournant.

codaddict
la source
2
Bonne réponse! +1
Jayesh Bhoi
18

C'est bien une boucle qui continue jusqu'à ce qu'une certaine condition soit remplie:

while(cantGoOn) {};
Oded
la source
1
Et / ou while (cantGoOn) {sleep (0)};
Jiminion
@Jiminion si vous mettez un, sleep(0)cela devancerait le thread, tuant le but d'utiliser un verrou tournant en premier lieu. si vous avez besoin de céder à d'autres threads, vous devriez utiliser un verrou normal. (Je sais que votre commentaire est très ancien mais je voulais empêcher les autres de voir cela comme une suggestion).
Sedat Kapanoglu
"Une valeur de zéro oblige le thread à abandonner le reste de sa tranche de temps à tout autre thread prêt à être exécuté. S'il n'y a aucun autre thread prêt à être exécuté, la fonction retourne immédiatement et le thread continue l'exécution."
Jiminion
8
 while(something != TRUE ){};
 // it happend
 move_on();
Luka Rahne
la source
5

C'est un type de serrure qui attend beaucoup

Il est considéré comme un anti-pattern, sauf pour la programmation de pilotes de très bas niveau (où il peut arriver que l'appel d'une fonction d'attente "correcte" ait plus de surcharge que le simple verrouillage occupé pendant quelques cycles).

Voir par exemple Spinlocks dans le noyau Linux .

conférence de Janes
la source
3

Les SpinLocks sont ceux dans lesquels le thread attend jusqu'à ce que le verrou soit disponible. Ceci sera normalement utilisé pour éviter la surcharge liée à l'obtention des objets du noyau lorsqu'il y a une possibilité d'acquérir l'objet du noyau dans un court laps de temps.

Ex:

While(SpinCount-- && Kernel Object is not free)
{}

try acquiring Kernel object
un J.
la source
3

Vous voudrez utiliser un verrou tournant lorsque vous pensez qu'il est moins coûteux d'entrer dans une boucle d'attente occupée et de regrouper une ressource au lieu de la bloquer lorsque la ressource est verrouillée.

La rotation peut être bénéfique lorsque les verrous sont à grain fin et en grand nombre (par exemple, un verrou par nœud dans une liste liée) ainsi que lorsque les temps de maintien des verrous sont toujours extrêmement courts. En général, tout en maintenant un verrou tournant, il faut éviter de bloquer, appeler tout ce qui peut lui-même bloquer, maintenir plus d'un verrou tournant à la fois, faire des appels distribués dynamiquement (interface et virtuels), faire des appels distribués statiquement dans n'importe quel code que l'on ne fait pas. t posséder ou allouer de la mémoire.

Il est également important de noter que SpinLock est un type valeur, pour des raisons de performances. En tant que tel, il faut être très prudent de ne pas copier accidentellement une instance SpinLock, car les deux instances (l'original et la copie) seraient alors complètement indépendantes l'une de l'autre, ce qui entraînerait probablement un comportement erroné de l'application. Si une instance SpinLock doit être transmise, elle doit être transmise par référence plutôt que par valeur.

NullReference
la source
1

En bref, spinlock utilise des instructions de comparaison et d'échange atomiques (CAS) ou des instructions de type test-and-set pour implémenter un idiome sans verrouillage et sans attente. De telles structures évoluent bien dans les machines multicœurs.

Chandra Patni
la source
Par définition, un verrou tournant n'est pas utilisé pour implémenter quoi que ce soit sans verrou ou sans attendre.
rdb
0

C'est une boucle qui tourne jusqu'à ce qu'une condition soit remplie.

dreamlax
la source
0

Eh bien, oui - le point des verrous de rotation (par rapport aux sections critiques traditionnelles, etc.) est qu'ils offrent de meilleures performances dans certaines circonstances (systèmes multicœurs ...), car ils ne donnent pas immédiatement le reste du quantum du thread.

Terry Mahaffey
la source
0

Spinlock, est un type de verrou, qui ne peut pas bloquer et ne peut pas dormir. Tout thread qui souhaite acquérir un verrou tournant pour une ressource partagée ou critique tournera continuellement, gaspillant le cycle de traitement du processeur jusqu'à ce qu'il acquière le verrou pour la ressource spécifiée. Une fois le verrou tournant acquis, il essaie de terminer le travail dans son quantum puis de libérer la ressource respectivement. Spinlock est le type de verrou le plus prioritaire, on peut simplement dire qu'il s'agit d'un type de verrou non préemptif.

akD
la source