Este artículo se tradujo automáticamente. Para ver el artículo en inglés, active la casilla Inglés. Además, puede mostrar el texto en inglés en una ventana emergente si mueve el puntero del mouse sobre el texto.
Traducción
Inglés

Clase ReaderWriterLock

 

Publicado: noviembre de 2016

Define un bloqueo que admite un escritor y varios lectores.

Espacio de nombres:   System.Threading
Ensamblado:  mscorlib (en mscorlib.dll)


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

NombreDescripción
System_CAPS_pubmethodReaderWriterLock()

Inicializa una nueva instancia de la clase ReaderWriterLock.

NombreDescripción
System_CAPS_pubpropertyIsReaderLockHeld

Obtiene un valor que indica si el subproceso actual tiene un bloqueo de lector.

System_CAPS_pubpropertyIsWriterLockHeld

Obtiene un valor que indica si el subproceso actual tiene el bloqueo de escritor.

System_CAPS_pubpropertyWriterSeqNum

Obtiene el número de secuencia actual.

NombreDescripción
System_CAPS_pubmethodAcquireReaderLock(Int32)

Adquiere un bloqueo de lector, utilizando un valor Int32 para el tiempo de espera.

System_CAPS_pubmethodAcquireReaderLock(TimeSpan)

Adquiere un bloqueo de lector, utilizando un valor TimeSpan para el tiempo de espera.

System_CAPS_pubmethodAcquireWriterLock(Int32)

Adquiere el bloqueo de escritor, utilizando un valor Int32 para el tiempo de espera.

System_CAPS_pubmethodAcquireWriterLock(TimeSpan)

Adquiere el bloqueo de escritor, utilizando un valor TimeSpan para el tiempo de espera.

System_CAPS_pubmethodAnyWritersSince(Int32)

Indica si se ha concedido el bloqueo de escritor a algún subproceso desde que se obtuvo el número de secuencia.

System_CAPS_pubmethodDowngradeFromWriterLock(LockCookie)

Recupera el estado de bloqueo del subproceso al estado que tenía antes de llamar a UpgradeToWriterLock.

System_CAPS_pubmethodEquals(Object)

Determina si el objeto especificado es igual al objeto actual.(Heredado de Object).

System_CAPS_protmethodFinalize()

Se asegura de que los recursos se liberan y que se llevan a cabo otras operaciones de limpieza cuando el recolector de elementos no utilizados recupere el objeto ReaderWriterLock.(Invalida CriticalFinalizerObject.Finalize()).

System_CAPS_pubmethodGetHashCode()

Sirve como la función hash predeterminada.(Heredado de Object).

System_CAPS_pubmethodGetType()

Obtiene el Type de la instancia actual.(Heredado de Object).

System_CAPS_pubmethodReleaseLock()

Libera el bloqueo, independientemente del número de veces que el subproceso haya adquirido el bloqueo.

System_CAPS_pubmethodReleaseReaderLock()

Reduce el recuento de bloqueos.

System_CAPS_pubmethodReleaseWriterLock()

Reduce el recuento de bloqueos del bloqueo de escritor.

System_CAPS_pubmethodRestoreLock(LockCookie)

Restaura el estado de bloqueo del subproceso al estado que tenía antes de llamar a ReleaseLock.

System_CAPS_pubmethodToString()

Devuelve una cadena que representa al objeto actual. (Heredado de Object).

System_CAPS_pubmethodUpgradeToWriterLock(Int32)

Actualiza un bloqueo de lector al bloqueo de escritor, utilizando un valor Int32 para el tiempo de espera.

System_CAPS_pubmethodUpgradeToWriterLock(TimeSpan)

Actualiza un bloqueo de lector al bloqueo de escritor utilizando un valor TimeSpan para el tiempo de espera.

System_CAPS_importantImportante

El .NET Framework tiene dos bloqueos de lector y escritor, ReaderWriterLockSlim y ReaderWriterLock. ReaderWriterLockSlim se recomienda para todo el desarrollo nuevo. ReaderWriterLockSlim es similar a ReaderWriterLock, pero simplificó las reglas de recursividad y para actualizar y degradar el estado del bloqueo. ReaderWriterLockSlim evita muchos casos de interbloqueo potencial. Además, el rendimiento de ReaderWriterLockSlim es significativamente mejor que ReaderWriterLock.

ReaderWriterLock se utiliza para sincronizar el acceso a un recurso. En cualquier momento dado, permite el acceso de lectura simultáneo de varios subprocesos, o bien acceso de escritura para un único subproceso. En una situación donde un recurso cambia con poca frecuencia, un ReaderWriterLock proporciona un mejor rendimiento que un simple bloqueo de uno en uno, como Monitor.

ReaderWriterLock funciona mejor cuando la mayoría de los accesos es de lectura y las escrituras son poco frecuentes y de corta duración. Se alternan varios lectores con escritores únicos, para que ni lectores ni a escritores se bloquean durante largos períodos.

System_CAPS_noteNota

Mantiene los bloqueos de lector o de escritores durante largos períodos privar a otros subprocesos. Para obtener el mejor rendimiento, considere la posibilidad de reestructuración de la aplicación para reducir la duración de las escrituras.

Un subproceso puede contener un lector de bloqueo o un bloqueo de escritor, pero no ambos al mismo tiempo. En lugar de liberar un bloqueo de lector para adquirir el bloqueo de escritor, puede utilizar UpgradeToWriterLock y DowngradeFromWriterLock.

Solicitudes de bloqueo recursivas aumentan el recuento de bloqueo en un bloqueo.

Los lectores y escritores se ponen en cola por separado. Cuando un subproceso libera el bloqueo de escritor, todos los subprocesos en espera en la cola del lector en ese momento se conceden bloqueos de lector; Cuando todos esos bloqueos de lector liberados, el siguiente subproceso en espera en el sistema de escritura de la cola, si los hay, se concede el bloqueo de escritor y así sucesivamente. En otras palabras, ReaderWriterLock alterna entre una colección de lectores y un escritor.

Mientras un subproceso en la cola del escritor está esperando a que se liberen los bloqueos de lector activo, los subprocesos que solicitan nuevos bloqueos de lector se acumulan en la cola del lector. Las solicitudes no se conceden, aunque podrían compartir el acceso simultáneo con propietarios de bloqueos de lector existentes; Esto ayuda a proteger a los escritores frente a bloqueos indefinidos por los lectores.

Mayoría de los métodos para adquirir bloqueos en un ReaderWriterLock Aceptar valores de tiempo de espera. Utilice los tiempos de espera para evitar interbloqueos en la aplicación. Por ejemplo, un subproceso podría adquirir el bloqueo de escritor en un recurso y, a continuación, solicitar un bloqueo de lector en un segundo recurso; mientras tanto, otro subproceso podría adquirir el bloqueo de escritura en el segundo recurso y solicitar un bloqueo de lector en el primero. A menos que se utilizan los tiempos de espera, el interbloqueo de subprocesos.

Si expira el intervalo de tiempo de espera y la solicitud de bloqueo no se ha concedido, el método devuelve el control al subproceso que realiza la llamada produciendo un ApplicationException. Un subproceso puede detectar esta excepción y determinar qué acción se debe realizar a continuación.

Los tiempos de espera se expresan en milisegundos. Si utiliza un System.TimeSpan para especificar el tiempo de espera, el valor utilizado es el número total de milisegundos completos representado por la TimeSpan. En la tabla siguiente se muestra los valores válidos de tiempo de espera en milisegundos.

Valor

Descripción

-1

El subproceso espera hasta que se adquiere el bloqueo, independientemente de cuánto tiempo lleva. Para los métodos que especifican tiempos de espera de entero, la constante Infinite se puede usar.

0

El subproceso no espera para adquirir el bloqueo. Si no se puede adquirir el bloqueo inmediatamente, el método devuelve.

>0

El número de milisegundos de espera.

A excepción de -1, no se permiten valores negativos del tiempo de espera. Si especifica un entero negativo distinto de -1, en su lugar se utiliza un valor de tiempo de espera de cero. (Es decir, el método devuelve sin esperar si el bloqueo no puede adquirirse inmediatamente). Si especifica un TimeSpan que representa un número negativo de milisegundos distinto de -1, ArgumentOutOfRangeException se produce.

En el ejemplo siguiente se muestra cómo utilizar un ReaderWriterLock para proteger un recurso compartido, un valor entero denominado resource, que se leen simultáneamente y escriben exclusivamente por varios subprocesos. Tenga en cuenta que el ReaderWriterLock se declara en el nivel de clase para que sea visible para todos los subprocesos.

// 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 desde 1.1

Este tipo es seguro para la ejecución de subprocesos.

Volver al principio
Mostrar: