Mes deux cents sur SpinLock dans .Net

Imaginez une situation dans laquelle un thread tente d'acquérir l'accès à une ressource partagée mais que la ressource est déjà verrouillée, le thread doit donc attendre que le verrou soit libéré. C'est là que la synchronisation des threads entre en jeu. La synchronisation des threads est utilisée pour empêcher plusieurs threads d'accéder simultanément à une ressource partagée. Microsoft .Net Framework prend en charge une gamme de primitives de synchronisation qui peuvent être utilisées pour contrôler le comportement des threads et éviter les conditions de concurrence. Mutex et Spinlock sont deux mécanismes de synchronisation populaires utilisés pour synchroniser l'accès à une ressource partagée.

Un SpinLock est une alternative au blocage de la synchronisation. SpinLock (également connu sous le nom de «Busy Waiting») est un mécanisme qui peut être utilisé pour faire en sorte qu'un thread essayant d'acquérir un verrou attende dans une boucle jusqu'à ce qu'il puisse accéder à la ressource. Notez que SpinLock peut fonctionner plus rapidement que Mutex car le changement de contexte est réduit. Cependant, vous ne devez utiliser SpinLocks que si la section critique est censée effectuer un minimum de travail, c'est-à-dire que le SpinLock est maintenu pendant une très courte période de temps. Les SpinLocks sont généralement préférés dans les systèmes multiprocesseurs symétriques pour interroger en permanence la disponibilité d'une ressource au lieu des changements de contexte.

Qu'est-ce que SpinLock et pourquoi est-il nécessaire?

SpinLock effectue une attente occupée et peut offrir de meilleures performances lorsqu'il est utilisé dans des systèmes multicœurs, en particulier lorsqu'il est bon marché d'attendre en boucle et de regrouper une ressource plutôt que de la bloquer. Ceci est particulièrement utile lorsque les temps de maintien des verrous sont de courte durée. En d'autres termes, vous pouvez tirer parti de SpinLock dans les systèmes multicœurs pour réduire la surcharge impliquée dans le changement de contexte si le temps à passer à l'intérieur de la section critique est petit. Une section critique peut être définie comme une structure de données ou une ressource partagée par plusieurs threads, mais un et un seul thread peut y avoir accès à un moment donné.

Il convient de noter que conserver SpinLock pendant une durée plus longue serait simplement un gaspillage des ressources du système et préjudiciable aux performances de l'application. Essentiellement, si vous vous attendez à ce que le blocage soit d'une durée significative, SpinLock ne doit jamais être utilisé - utilisez SpinLock uniquement lorsque les temps de maintien du verrou sont d'une durée raisonnablement petite.

SpinLock est généralement utilisé lorsque vous travaillez avec des interruptions pour effectuer une attente occupée dans une boucle jusqu'à ce que la ressource soit rendue disponible. SpinLock ne provoque pas la préemption du thread, mais continue à tourner jusqu'à ce que le verrouillage de la ressource soit libéré.

Programmation de SpinLock en .Net

Notez qu'un SpinLock est défini comme une structure dans .Net, c'est-à-dire qu'il est défini comme un type valeur pour des raisons de performances. Par conséquent, si vous transmettez une instance SpinLock, vous devez la transmettre par référence et non par valeur. Dans cette section, nous explorerons comment programmer SpinLock en .Net. Pour implémenter SpinLock dans .Net, vous devez tirer parti de la classe SpinLock disponible dans l'espace de noms System.Threading.

La liste de codes suivante montre comment vous pouvez utiliser SpinLock dans .Net.

SpinLock spinLock = new SpinLock (true);

bool isLocked = false;

try

{

spinLock.Enter (ref isLocked);

// Write your usual code here

}

finally

{

if (isLocked)

   spinLock.Exit();

}

SpinWait

Notez que comme SpinLock, SpinWait est également une structure et non une classe. Similaire à SpinLock, vous pouvez utiliser SpinWait pour écrire du code de synchronisation sans verrou qui peut "tourner" plutôt que bloquer. SpinWait peut être utilisé pour réduire la consommation de ressources en effectuant une rotation intensive du processeur pendant 10 itérations après lesquelles il cédera le contrôle en appelant Thread.Yield et Thread.Sleep. En d'autres termes, SpinWait peut être utilisé pour limiter la rotation gourmande en CPU à un nombre fixe d'itérations. Le MSDN déclare: «System.Threading.SpinWait est un type de synchronisation léger que vous pouvez utiliser dans des scénarios de bas niveau pour éviter les changements de contexte coûteux et les transitions de noyau qui sont nécessaires pour les événements du noyau».

Pour utiliser SpinWait dans votre code, vous pouvez soit tirer parti de la méthode statique SpinUntil () de la structure SpinWait, soit tirer parti de sa méthode non statique SpinOnce (). L'extrait de code suivant illustre comment SpinWait peut être utilisé.

SpinWait spinWait = new SpinWait();

bool shouldSpin;

while (!shouldSpin)

{

   Thread.MemoryBarrier(); spinWait.SpinOnce();

}