Cet article a fait l’objet d’une traduction automatique. Pour afficher l’article en anglais, activez la case d’option Anglais. Vous pouvez également afficher le texte anglais dans une fenêtre contextuelle en faisant glisser le pointeur de la souris sur le texte traduit.
Traduction
Anglais

ReaderWriterLock classe

 

Date de publication : novembre 2016

Définit un verrou qui prend en charge les writers uniques et les lecteurs multiples.

Espace de noms:   System.Threading
Assembly:  mscorlib (dans mscorlib.dll)


[ComVisibleAttribute(true)]
[HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization = true, 
	ExternalThreading = true)]
public sealed class ReaderWriterLock : CriticalFinalizerObject

NomDescription
System_CAPS_pubmethodReaderWriterLock()

Initialise une nouvelle instance de la classe ReaderWriterLock.

NomDescription
System_CAPS_pubpropertyIsReaderLockHeld

Obtient une valeur indiquant si le thread actif détient un verrou de lecteur.

System_CAPS_pubpropertyIsWriterLockHeld

Obtient une valeur indiquant si le thread actif détient le verrou de writer.

System_CAPS_pubpropertyWriterSeqNum

Obtient le numéro de séquence actuel.

NomDescription
System_CAPS_pubmethodAcquireReaderLock(Int32)

Acquiert un verrou de lecteur en utilisant une valeur Int32 comme délai d'attente.

System_CAPS_pubmethodAcquireReaderLock(TimeSpan)

Acquiert un verrou de lecteur en utilisant une valeur TimeSpan comme délai d'attente.

System_CAPS_pubmethodAcquireWriterLock(Int32)

Acquiert un verrou de writer en utilisant une valeur Int32 comme délai d'attente.

System_CAPS_pubmethodAcquireWriterLock(TimeSpan)

Acquiert un verrou de writer en utilisant une valeur TimeSpan comme délai d'attente.

System_CAPS_pubmethodAnyWritersSince(Int32)

Indique si le verrou de writer a été accordé à un thread depuis l'obtention du numéro de séquence.

System_CAPS_pubmethodDowngradeFromWriterLock(LockCookie)

Restaure le verrou du thread à l'état qu'il avait avant l'appel à UpgradeToWriterLock.

System_CAPS_pubmethodEquals(Object)

Détermine si l'objet spécifié est identique à l'objet actuel.(Hérité de Object.)

System_CAPS_protmethodFinalize()

Vérifie que les ressources sont libérées et que toute autre opération de nettoyage est effectuée quand le garbage collector récupère l'objet ReaderWriterLock.(Remplace CriticalFinalizerObject.Finalize().)

System_CAPS_pubmethodGetHashCode()

Fait office de fonction de hachage par défaut.(Hérité de Object.)

System_CAPS_pubmethodGetType()

Obtient le Type de l'instance actuelle.(Hérité de Object.)

System_CAPS_pubmethodReleaseLock()

Libère le verrou quel que soit le nombre de fois où il a été acquis par le thread.

System_CAPS_pubmethodReleaseReaderLock()

Décrémente le nombre de verrous.

System_CAPS_pubmethodReleaseWriterLock()

Décrémente le nombre de verrous sur le verrou de writer.

System_CAPS_pubmethodRestoreLock(LockCookie)

Restaure l'état de verrou du thread au moment précédant l'appel à ReleaseLock.

System_CAPS_pubmethodToString()

Retourne une chaîne qui représente l'objet actuel.(Hérité de Object.)

System_CAPS_pubmethodUpgradeToWriterLock(Int32)

Met à niveau un verrou de lecteur vers le verrou de writer en utilisant une valeur Int32 pour définir le délai d'attente.

System_CAPS_pubmethodUpgradeToWriterLock(TimeSpan)

Met à niveau un verrou de lecteur vers le verrou de writer en utilisant une valeur TimeSpan pour définir le délai d'attente.

System_CAPS_importantImportant

Le .NET Framework a deux verrous de lecteur-writer, ReaderWriterLockSlim et ReaderWriterLock. ReaderWriterLockSlim est recommandé pour tout nouveau développement. ReaderWriterLockSlim est similaire à ReaderWriterLock, mais les règles de récurrence et de mise à niveau et la rétrogradation de l’état de verrou sont simplifiées. ReaderWriterLockSlim évite de nombreux cas d’interblocage potentiel. En outre, les performances de ReaderWriterLockSlim est nettement supérieure à ReaderWriterLock.

ReaderWriterLock est utilisé pour synchroniser l’accès à une ressource. À un moment donné, il permet un accès en lecture simultané de plusieurs threads, ou un accès en écriture pour un seul thread. Dans une situation où une ressource est modifiée en de rares occasions, un ReaderWriterLock fournit une productivité supérieure à un verrou d’un-à-à la fois simple, tel que Monitor.

ReaderWriterLock fonctionne mieux lorsque la plupart des accès sont des lectures, en écriture sont rares et de courte durée. Les lecteurs multiples alternent avec les writers uniques afin que ni les lectures ni les écritures sont bloquées pendant de longues périodes.

System_CAPS_noteRemarque

Maintenir les verrous de lecteur ou de writer pendant de longues périodes retarde l’exécution d’autres threads. Pour de meilleures performances, pensez à restructurer votre application afin de réduire la durée des écritures.

Un thread peut contenir un lecteur de verrou ou un verrou de writer, mais pas les deux en même temps. Au lieu de libérer un verrou de lecteur pour acquérir le verrou de writer, vous pouvez utiliser UpgradeToWriterLock et DowngradeFromWriterLock.

Demandes de verrou récursives augmenter le nombre de verrous sur un verrou.

Lecteurs et writers sont en file d’attente séparément. Lorsqu’un thread libère le verrou de writer, tous les threads en attente dans la file d’attente de lecture instantanée bénéficient de verrous de lecteur. Lorsque tous ces verrous de lecteur ont été publiées, l’attente de thread suivant dans l’enregistreur de file d’attente, si un, est accordé le verrou de writer et ainsi de suite. En d’autres termes, ReaderWriterLock alterne entre une collection de lecteurs et un seul writer.

Lorsqu’un thread dans la file d’attente de l’enregistreur est en attente de libération de verrous lecteur actif, les threads demandant de nouveaux verrous de lecteur s’accumulent dans la file d’attente du lecteur. Leurs demandes ne sont pas accordées, bien qu’ils peuvent partager un accès simultané avec des détenteurs de verrous de lecteur existants ; Cela permet de protéger les rédacteurs pour un blocage indéfini par les lecteurs.

La plupart des méthodes d’acquisition de verrous sur un ReaderWriterLock accepte les valeurs de délai d’attente. Utilisez les délais pour éviter les blocages dans votre application. Par exemple, un thread peut acquérir le verrou de writer sur une ressource et ensuite demander un verrou de lecteur sur une seconde ressource ; entre-temps, un autre thread peut acquérir le verrou de writer sur la seconde ressource et demander un verrou de lecteur sur le premier. Sauf si les délais d’attente sont utilisés, le blocage des threads.

Si l’intervalle de délai d’attente expire et que la demande de verrou n’a pas été accordée, la méthode retourne le contrôle au thread appelant en levant une ApplicationException. Un thread peut intercepter cette exception et déterminer l’action à entreprendre.

Les délais d’attente sont exprimées en millisecondes. Si vous utilisez un System.TimeSpan pour spécifier le délai d’attente, la valeur utilisée est le nombre total de millisecondes entières représenté par le TimeSpan. Le tableau suivant indique les valeurs de délai d’attente valides en millisecondes.

Valeur

Description

-1

Le thread attend jusqu'à ce que le verrou est acquis, quelle que soit sa durée. Pour les méthodes qui spécifient des délais d’expiration entiers, la constante Infinite peut être utilisé.

0

Le thread n’attend pas pour acquérir le verrou. Si le verrou ne peut pas être acquis immédiatement, la méthode retourne.

>0

Le nombre de millisecondes à attendre.

À l’exception de -1, les délais d’attente négatifs ne sont pas autorisés. Si vous spécifiez un entier négatif autre que -1, une valeur égale à zéro est utilisée à la place. (Autrement dit, la méthode retourne sans attendre si le verrou ne peut pas être acquis immédiatement.) Si vous spécifiez un TimeSpan qui représente un nombre négatif de millisecondes autre que -1, ArgumentOutOfRangeException est levée.

L’exemple suivant montre comment utiliser un ReaderWriterLock pour protéger une ressource partagée, un entier nommé resource, qui est lue simultanément et est écrite exclusivement par plusieurs threads. Notez que le ReaderWriterLock est déclarée au niveau de la classe afin qu’il soit visible par tous les threads.

// The complete code is located in the ReaderWriterLock class topic.
using System;
using System.Threading;

public class Example
{
   static ReaderWriterLock rwl = new ReaderWriterLock();
   // Define the shared resource protected by the ReaderWriterLock.
   static int resource = 0;

   const int numThreads = 26;
   static bool running = true;
   static Random rnd = new Random();

   // Statistics.
   static int readerTimeouts = 0;
   static int writerTimeouts = 0;
   static int reads = 0;
   static int writes = 0;

   public static void Main()
   {
      // Start a series of threads to randomly read from and
      // write to the shared resource.
      Thread[] t = new Thread[numThreads];
      for (int i = 0; i < numThreads; i++){
         t[i] = new Thread(new ThreadStart(ThreadProc));
         t[i].Name = new String(Convert.ToChar(i + 65), 1);
         t[i].Start();
         if (i > 10)
            Thread.Sleep(300);
      }

      // Tell the threads to shut down and wait until they all finish.
      running = false;
      for (int i = 0; i < numThreads; i++)
         t[i].Join();

      // Display statistics.
      Console.WriteLine("\n{0} reads, {1} writes, {2} reader time-outs, {3} writer time-outs.",
            reads, writes, readerTimeouts, writerTimeouts);
      Console.Write("Press ENTER to exit... ");
      Console.ReadLine();
   }

   static void ThreadProc()
   {
      // Randomly select a way for the thread to read and write from the shared
      // resource.
      while (running) {
         double action = rnd.NextDouble();
         if (action < .8)
            ReadFromResource(10);
         else if (action < .81)
            ReleaseRestore(50);
         else if (action < .90)
            UpgradeDowngrade(100);
         else
            WriteToResource(100);
      }
   }

   // Request and release a reader lock, and handle time-outs.
   static void ReadFromResource(int timeOut)
   {
      try {
         rwl.AcquireReaderLock(timeOut);
         try {
            // It is safe for this thread to read from the shared resource.
            Display("reads resource value " + resource);
            Interlocked.Increment(ref reads);
         }
         finally {
            // Ensure that the lock is released.
            rwl.ReleaseReaderLock();
         }
      }
      catch (ApplicationException) {
         // The reader lock request timed out.
         Interlocked.Increment(ref readerTimeouts);
      }
   }

   // Request and release the writer lock, and handle time-outs.
   static void WriteToResource(int timeOut)
   {
      try {
         rwl.AcquireWriterLock(timeOut);
         try {
            // It's safe for this thread to access from the shared resource.
            resource = rnd.Next(500);
            Display("writes resource value " + resource);
            Interlocked.Increment(ref writes);
         }
         finally {
            // Ensure that the lock is released.
            rwl.ReleaseWriterLock();
         }
      }
      catch (ApplicationException) {
         // The writer lock request timed out.
         Interlocked.Increment(ref writerTimeouts);
      }
   }

   // Requests a reader lock, upgrades the reader lock to the writer
   // lock, and downgrades it to a reader lock again.
   static void UpgradeDowngrade(int timeOut)
   {
      try {
         rwl.AcquireReaderLock(timeOut);
         try {
            // It's safe for this thread to read from the shared resource.
            Display("reads resource value " + resource);
            Interlocked.Increment(ref reads);

            // To write to the resource, either release the reader lock and
            // request the writer lock, or upgrade the reader lock. Upgrading
            // the reader lock puts the thread in the write queue, behind any
            // other threads that might be waiting for the writer lock.
            try {
               LockCookie lc = rwl.UpgradeToWriterLock(timeOut);
               try {
                  // It's safe for this thread to read or write from the shared resource.
                  resource = rnd.Next(500);
                  Display("writes resource value " + resource);
                  Interlocked.Increment(ref writes);
               }
               finally {
                  // Ensure that the lock is released.
                  rwl.DowngradeFromWriterLock(ref lc);
               }
            }
            catch (ApplicationException) {
               // The upgrade request timed out.
               Interlocked.Increment(ref writerTimeouts);
            }

            // If the lock was downgraded, it's still safe to read from the resource.
            Display("reads resource value " + resource);
            Interlocked.Increment(ref reads);
         }
         finally {
            // Ensure that the lock is released.
            rwl.ReleaseReaderLock();
         }
      }
      catch (ApplicationException) {
         // The reader lock request timed out.
         Interlocked.Increment(ref readerTimeouts);
      }
   }

   // Release all locks and later restores the lock state.
   // Uses sequence numbers to determine whether another thread has
   // obtained a writer lock since this thread last accessed the resource.
   static void ReleaseRestore(int timeOut)
   {
      int lastWriter;

      try {
         rwl.AcquireReaderLock(timeOut);
         try {
            // It's safe for this thread to read from the shared resource,
            // so read and cache the resource value.
            int resourceValue = resource;     // Cache the resource value.
            Display("reads resource value " + resourceValue);
            Interlocked.Increment(ref reads);

            // Save the current writer sequence number.
            lastWriter = rwl.WriterSeqNum;

            // Release the lock and save a cookie so the lock can be restored later.
            LockCookie lc = rwl.ReleaseLock();

            // Wait for a random interval and then restore the previous state of the lock.
            Thread.Sleep(rnd.Next(250));
            rwl.RestoreLock(ref lc);

            // Check whether other threads obtained the writer lock in the interval.
            // If not, then the cached value of the resource is still valid.
            if (rwl.AnyWritersSince(lastWriter)) {
               resourceValue = resource;
               Interlocked.Increment(ref reads);
               Display("resource has changed " + resourceValue);
            }
            else {
               Display("resource has not changed " + resourceValue);
            }
         }
         finally {
            // Ensure that the lock is released.
            rwl.ReleaseReaderLock();
         }
      }
      catch (ApplicationException) {
         // The reader lock request timed out.
         Interlocked.Increment(ref readerTimeouts);
      }
   }

   // Helper method briefly displays the most recent thread action.
   static void Display(string msg)
   {
      Console.Write("Thread {0} {1}.       \r", Thread.CurrentThread.Name, msg);
   }
}

.NET Framework
Disponible depuis 1.1

Ce type est thread-safe.

Retour au début
Afficher: