Exportar (0) Imprimir
Expandir todo
Este artículo proviene de un motor de traducción automática. Mueva el puntero sobre las frases del artículo para ver el texto original. Más información.
Traducción
Original

ReaderWriterLock (Clase)

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

El tipo ReaderWriterLock expone los siguientes miembros.

  NombreDescripción
Método públicoReaderWriterLockInicializa una nueva instancia de la clase ReaderWriterLock.
Arriba

  NombreDescripción
Propiedad públicaIsReaderLockHeldObtiene un valor que indica si el subproceso actual tiene el bloqueo de lector.
Propiedad públicaIsWriterLockHeldObtiene un valor que indica si el subproceso actual tiene el bloqueo de escritor.
Propiedad públicaWriterSeqNumObtiene el número de secuencia actual.
Arriba

  NombreDescripción
Método públicoAcquireReaderLock(Int32)Adquiere un bloqueo de lector, utilizando un valor Int32 para el tiempo de espera.
Método públicoAcquireReaderLock(TimeSpan)Adquiere un bloqueo de lector, utilizando un valor TimeSpan para el tiempo de espera.
Método públicoAcquireWriterLock(Int32)Adquiere un bloqueo de escritor, utilizando un valor Int32 para el tiempo de espera.
Método públicoAcquireWriterLock(TimeSpan)Adquiere un bloqueo de escritor, utilizando un valor TimeSpan para el tiempo de espera.
Método públicoAnyWritersSinceIndica si se ha concedido el bloqueo de escritor a algún subproceso desde que se obtuvo el número de secuencia.
Método públicoDowngradeFromWriterLockRestaura el estado de bloqueo del subproceso al estado que tenía antes de llamar a UpgradeToWriterLock.
Método públicoEquals(Object)Determina si el objeto especificado es igual al objeto actual. (Se hereda de Object).
Método públicoGetHashCode Sirve como una función hash para un tipo en particular. (Se hereda de Object).
Método públicoGetType Obtiene el Type de la instancia actual. (Se hereda de Object).
Método públicoReleaseLockLibera el bloqueo, independientemente del número de veces que el subproceso haya adquirido el bloqueo.
Método públicoReleaseReaderLockReduce el recuento de bloqueos.
Método públicoReleaseWriterLockReduce el recuento de bloqueos del bloqueo de escritor.
Método públicoRestoreLockRestaura el estado de bloqueo del subproceso al estado que tenía antes de llamar a ReleaseLock.
Método públicoToString Retorna una cadena que representa al objeto actual. (Se hereda de Object).
Método públicoUpgradeToWriterLock(Int32)Actualiza un bloqueo de lector al bloqueo de escritor, utilizando un valor Int32 para el tiempo de espera.
Método públicoUpgradeToWriterLock(TimeSpan)Actualiza un bloqueo de lector al bloqueo de escritor utilizando un valor TimeSpan para el tiempo de espera.
Arriba

Nota importanteImportante

.NET Framework dispone de dos bloqueos de lector y escritor, ReaderWriterLockSlim y ReaderWriterLock. ReaderWriterLockSlim se recomienda para todos los trabajos de desarrollo nuevos. ReaderWriterLockSlim es similar a ReaderWriterLock, pero tiene reglas simplificadas para la 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 el acceso de escritura de un solo subproceso. En una situación en la que un recurso se cambia raramente, ReaderWriterLock proporciona mejor rendimiento que un simple bloqueo de uno en uno, como Monitor.

ReaderWriterLock funciona mejor si la mayoría de los accesos son de lectura y las escrituras son pocas y de corta duración. Se alternan varios lectores con escritores únicos, para que ni lectores ni escritores queden bloqueados largos períodos de tiempo.

NotaNota

Si se mantienen bloqueos de lectores o de escritores durante largos períodos de tiempo, otros subprocesos quedarán sin recursos. Para obtener un mejor rendimiento, se puede reestructurar la aplicación de manera que se minimice la duración de las escrituras.

Un subproceso puede contener un bloqueo de lector o de escritor, pero no los dos a la vez. En lugar de liberar un bloqueo de lector para adquirir el bloqueo de escritor, se puede utilizar UpgradeToWriterLock y DowngradeFromWriterLock.

Las solicitudes de bloqueo recursivas aumentan el recuento de bloqueos de un bloqueo.

Los lectores y los escritores forman colas independientes. Cuando un subproceso libera el bloqueo del escritor, todos los subprocesos en espera de la cola del lector reciben en ese momento bloqueos de lector; cuando se liberan todos esos bloqueos de lector, el siguiente subproceso en espera de la cola del escritor, si lo hay, recibe un bloqueo de escritor, y así sucesivamente. En otras palabras, ReaderWriterLock alterna entre una colección de lectores y un escritor.

Si hay un subproceso en la cola del escritor esperando a que se liberen bloqueos activos de lector, los subprocesos que solicitan nuevos bloqueos de lector se acumulan en la cola del lector. Estas solicitudes no se conceden, aunque podrían compartir el acceso simultáneo con propietarios de bloqueos de lector existentes; de esta forma se ayuda a proteger a los escritores frente a bloqueos indefinidos por parte de los lectores.

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

Si expira el 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 ApplicationException. Un subproceso puede detectar esta excepción y decidir qué se debe hacer a continuación.

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

Valor

Descripción

-1

El subproceso espera hasta que se adquiere el bloqueo, sin tener en cuenta el tiempo que tarda. Para los métodos que especifican tiempos de espera enteros, se puede usar la constante Infinite.

0

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

>0

Número de milisegundos durante los que se va a esperar.

A excepción de -1, no se permiten valores de tiempo de espera negativos. Si se especifica un entero negativo distinto de -1, se usa un valor de tiempo de espera cero (es decir, el método regresa sin esperar si no se puede adquirir el bloqueo inmediatamente). Si se especifica un TimeSpan que representa un número negativo de milisegundos que no sea -1, se produce ArgumentOutOfRangeException.

NotaNota

El atributo HostProtectionAttribute aplicado a este tipo o miembro tiene el valor de propiedad Resources siguiente: Synchronization | ExternalThreading. El atributo HostProtectionAttribute no afecta a las aplicaciones de escritorio (que normalmente se inician haciendo doble clic en un icono, escribiendo un comando o introduciendo una dirección URL en el explorador). Para obtener más información, vea la clase HostProtectionAttribute o Programación en SQL Server y atributos de protección de host.

El ejemplo siguiente muestra cómo utilizar ReaderWriterLock para proteger un recurso compartido que varios subprocesos leen de forma concurrente y escriben de forma exclusiva.


// This example shows a ReaderWriterLock protecting a shared
// resource that is read concurrently and written exclusively
// by multiple threads.

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

public class Test
{
    // Declaring the ReaderWriterLock at the class level
    // makes it visible to all threads.
    static ReaderWriterLock rwl = new ReaderWriterLock();
    // For this example, the shared resource protected by the
    // ReaderWriterLock is just an integer.
    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(string[] args)
    {
        // Start a series of threads. Each thread randomly
        // performs reads and writes on 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, then wait until they all
        // finish.
        running = false;
        for (int i = 0; i < numThreads; i++)
        {
            t[i].Join();
        }

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

    static void ThreadProc()
    {
        // As long as a thread runs, it randomly selects
        // various ways to read and write from the shared 
        // resource. Each of the methods demonstrates one 
        // or more features of ReaderWriterLock.
        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);
        }
    }

    // Shows how to request and release a reader lock, and
    // how to 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);
        }
    }

    // Shows how to request and release the writer lock, and
    // how to handle time-outs.
    static void WriteToResource(int timeOut)
    {
        try
        {
            rwl.AcquireWriterLock(timeOut);
            try
            {
                // It is 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.ReleaseWriterLock();
            }
        }
        catch (ApplicationException)
        {
            // The writer lock request timed out.
            Interlocked.Increment(ref writerTimeouts);
        }
    }

    // Shows how to request a reader lock, upgrade the
    // reader lock to the writer lock, and downgrade to a
    // reader lock again.
    static void UpgradeDowngrade(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);

                // If it is necessary to write to the resource,
                // you must either release the reader lock and 
                // then request the writer lock, or upgrade the
                // reader lock. Note that 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 is 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);
                }

                // When the lock has been downgraded, it is 
                // 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);
        }
    }

    // Shows how to release all locks and later restore
    // the lock state. Shows how to use 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 is safe for this thread to read from
                // the shared resource. Cache the value. (You
                // might do this if reading the resource is
                // an expensive operation.)
                int resourceValue = resource;
                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 (up to a 
                // quarter of a second), and then restore
                // the previous state of the lock. Note that
                // there is no time-out on the Restore method.
                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. Comment out calls to Display to 
    // get a better idea of throughput.
    static void Display(string msg)
    {
        Console.Write("Thread {0} {1}.       \r", Thread.CurrentThread.Name, msg);
    }
}


.NET Framework

Compatible con: 4.5, 4, 3.5, 3.0, 2.0, 1.1, 1.0

.NET Framework Client Profile

Compatible con: 4, 3.5 SP1

Windows 8.1, Windows Server 2012 R2, Windows 8, Windows Server 2012, Windows 7, Windows Vista SP2, Windows Server 2008 (no se admite el rol Server Core), Windows Server 2008 R2 (se admite el rol Server Core con SP1 o versiones posteriores; no se admite Itanium)

.NET Framework no admite todas las versiones de todas las plataformas. Para obtener una lista de las versiones compatibles, vea Requisitos de sistema de .NET Framework.

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

Adiciones de comunidad

AGREGAR
Mostrar:
© 2014 Microsoft