Sugerir traducción
 
Otros han sugerido:

progress indicator
No hay más sugerencias.
Califique este contenido
Contraer todo/Expandir todo Contraer todo
Ver contenido:  en paraleloVer contenido: en paralelo
.NET Framework Class Library
ReaderWriterLockSlim Class

Represents a lock that is used to manage access to a resource, allowing multiple threads for reading or exclusive access for writing.

System..::.Object
  System.Threading..::.ReaderWriterLockSlim

Namespace:  System.Threading
Assembly:  System.Core (in System.Core.dll)
Visual Basic
<HostProtectionAttribute(SecurityAction.LinkDemand, MayLeakOnAbort := True)> _
<HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization := True,  _
    ExternalThreading := True)> _
Public Class ReaderWriterLockSlim _
    Implements IDisposable
C#
[HostProtectionAttribute(SecurityAction.LinkDemand, MayLeakOnAbort = true)]
[HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization = true, 
    ExternalThreading = true)]
public class ReaderWriterLockSlim : IDisposable
Visual C++
[HostProtectionAttribute(SecurityAction::LinkDemand, MayLeakOnAbort = true)]
[HostProtectionAttribute(SecurityAction::LinkDemand, Synchronization = true, 
    ExternalThreading = true)]
public ref class ReaderWriterLockSlim : IDisposable
F#
[<HostProtectionAttribute(SecurityAction.LinkDemand, MayLeakOnAbort = true)>]
[<HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization = true, 
    ExternalThreading = true)>]
type ReaderWriterLockSlim =  
    class
        interface IDisposable
    end

The ReaderWriterLockSlim type exposes the following members.

  NameDescription
Public methodReaderWriterLockSlim()()()Initializes a new instance of the ReaderWriterLockSlim class with default property values.
Public methodReaderWriterLockSlim(LockRecursionPolicy)Initializes a new instance of the ReaderWriterLockSlim class, specifying the lock recursion policy.
Top
  NameDescription
Public propertyCurrentReadCountGets the total number of unique threads that have entered the lock in read mode.
Public propertyIsReadLockHeldGets a value that indicates whether the current thread has entered the lock in read mode.
Public propertyIsUpgradeableReadLockHeldGets a value that indicates whether the current thread has entered the lock in upgradeable mode.
Public propertyIsWriteLockHeldGets a value that indicates whether the current thread has entered the lock in write mode.
Public propertyRecursionPolicyGets a value that indicates the recursion policy for the current ReaderWriterLockSlim object.
Public propertyRecursiveReadCountGets the number of times the current thread has entered the lock in read mode, as an indication of recursion.
Public propertyRecursiveUpgradeCountGets the number of times the current thread has entered the lock in upgradeable mode, as an indication of recursion.
Public propertyRecursiveWriteCountGets the number of times the current thread has entered the lock in write mode, as an indication of recursion.
Public propertyWaitingReadCountGets the total number of threads that are waiting to enter the lock in read mode.
Public propertyWaitingUpgradeCountGets the total number of threads that are waiting to enter the lock in upgradeable mode.
Public propertyWaitingWriteCountGets the total number of threads that are waiting to enter the lock in write mode.
Top
  NameDescription
Public methodDisposeReleases all resources used by the current instance of the ReaderWriterLockSlim class.
Public methodEnterReadLockTries to enter the lock in read mode.
Public methodEnterUpgradeableReadLockTries to enter the lock in upgradeable mode.
Public methodEnterWriteLockTries to enter the lock in write mode.
Public methodEquals(Object)Determines whether the specified Object is equal to the current Object. (Inherited from Object.)
Public methodExitReadLockReduces the recursion count for read mode, and exits read mode if the resulting count is 0 (zero).
Public methodExitUpgradeableReadLockReduces the recursion count for upgradeable mode, and exits upgradeable mode if the resulting count is 0 (zero).
Public methodExitWriteLockReduces the recursion count for write mode, and exits write mode if the resulting count is 0 (zero).
Protected methodFinalizeAllows an object to try to free resources and perform other cleanup operations before it is reclaimed by garbage collection. (Inherited from Object.)
Public methodGetHashCodeServes as a hash function for a particular type. (Inherited from Object.)
Public methodGetTypeGets the Type of the current instance. (Inherited from Object.)
Protected methodMemberwiseCloneCreates a shallow copy of the current Object. (Inherited from Object.)
Public methodToStringReturns a string that represents the current object. (Inherited from Object.)
Public methodTryEnterReadLock(Int32)Tries to enter the lock in read mode, with an optional integer time-out.
Public methodTryEnterReadLock(TimeSpan)Tries to enter the lock in read mode, with an optional time-out.
Public methodTryEnterUpgradeableReadLock(Int32)Tries to enter the lock in upgradeable mode, with an optional time-out.
Public methodTryEnterUpgradeableReadLock(TimeSpan)Tries to enter the lock in upgradeable mode, with an optional time-out.
Public methodTryEnterWriteLock(Int32)Tries to enter the lock in write mode, with an optional time-out.
Public methodTryEnterWriteLock(TimeSpan)Tries to enter the lock in write mode, with an optional time-out.
Top

Use ReaderWriterLockSlim to protect a resource that is read by multiple threads and written to by one thread at a time. ReaderWriterLockSlim allows multiple threads to be in read mode, allows one thread to be in write mode with exclusive ownership of the lock, and allows one thread that has read access to be in upgradeable read mode, from which the thread can upgrade to write mode without having to relinquish its read access to the resource.

NoteNote

ReaderWriterLockSlim is similar to ReaderWriterLock, but it has simplified rules for recursion and for upgrading and downgrading lock state. ReaderWriterLockSlim avoids many cases of potential deadlock. In addition, the performance of ReaderWriterLockSlim is significantly better than ReaderWriterLock. ReaderWriterLockSlim is recommended for all new development.

By default, new instances of ReaderWriterLockSlim are created with the LockRecursionPolicy..::.NoRecursion flag and do not allow recursion. This default policy is recommended for all new development, because recursion introduces unnecessary complications and makes your code more prone to deadlocks. To simplify migration from existing projects that use Monitor or ReaderWriterLock, you can use the LockRecursionPolicy..::.SupportsRecursion flag to create instances of ReaderWriterLockSlim that allow recursion.

A thread can enter the lock in three modes: read mode, write mode, and upgradeable read mode. (In the rest of this topic, "upgradeable read mode" is referred to as "upgradeable mode", and the phrase "enter x mode" is used in preference to the longer phrase "enter the lock in x mode".)

Regardless of recursion policy, only one thread can be in write mode at any time. When a thread is in write mode, no other thread can enter the lock in any mode. Only one thread can be in upgradeable mode at any time. Any number of threads can be in read mode, and there can be one thread in upgradeable mode while other threads are in read mode.

ReaderWriterLockSlim has managed thread affinity; that is, each Thread object must make its own method calls to enter and exit lock modes. No thread can change the mode of another thread.

If a ReaderWriterLockSlim does not allow recursion, a thread that tries to enter the lock can block for several reasons:

  • A thread that tries to enter read mode blocks if there are threads waiting to enter write mode or if there is a single thread in write mode.

    NoteNote

    Blocking new readers when writers are queued is a lock fairness policy that favors writers. The current fairness policy balances fairness to readers and writers, to promote throughput in the most common scenarios. Future versions of the .NET Framework may introduce new fairness policies.

  • A thread that tries to enter upgradeable mode blocks if there is already a thread in upgradeable mode, if there are threads waiting to enter write mode, or if there is a single thread in write mode.

  • A thread that tries to enter write mode blocks if there is a thread in any of the three modes.

Upgrading and Downgrading Locks

Upgradeable mode is intended for cases where a thread usually reads from the protected resource, but might need to write to it if some condition is met. A thread that has entered a ReaderWriterLockSlim in upgradeable mode has read access to the protected resource, and can upgrade to write mode by calling the EnterWriteLock or TryEnterWriteLock methods. Because there can be only one thread in upgradeable mode at a time, upgrading to write mode cannot deadlock when recursion is not allowed, which is the default policy.

Important noteImportant

Regardless of recursion policy, a thread that initially entered read mode is not allowed to upgrade to upgradeable mode or write mode, because that pattern creates a strong probability of deadlocks. For example, if two threads in read mode both try to enter write mode, they will deadlock. Upgradeable mode is designed to avoid such deadlocks.

If there are other threads in read mode, the thread that is upgrading blocks. While the thread is blocked, other threads that try to enter read mode are blocked. When all threads have exited from read mode, the blocked upgradeable thread enters write mode. If there are other threads waiting to enter write mode, they remain blocked, because the single thread that is in upgradeable mode prevents them from gaining exclusive access to the resource.

When the thread in upgradeable mode exits write mode, other threads that are waiting to enter read mode can do so, unless there are threads waiting to enter write mode. The thread in upgradeable mode can upgrade and downgrade indefinitely, as long as it is the only thread that writes to the protected resource.

Important noteImportant

If you allow multiple threads to enter write mode or upgradeable mode, you must not allow one thread to monopolize upgradeable mode. Otherwise, threads that try to enter write mode directly will be blocked indefinitely, and while they are blocked, other threads will be unable to enter read mode.

A thread in upgradeable mode can downgrade to read mode by first calling the EnterReadLock method and then calling the ExitUpgradeableReadLock method. This downgrade pattern is allowed for all lock recursion policies, even NoRecursion.

After downgrading to read mode, a thread cannot reenter upgradeable mode until it has exited from read mode.

Entering the Lock Recursively

You can create a ReaderWriterLockSlim that supports recursive lock entry by using the ReaderWriterLockSlim(LockRecursionPolicy) constructor that specifies lock policy, and specifying LockRecursionPolicy..::.SupportsRecursion.

NoteNote

The use of recursion is not recommended for new development, because it introduces unnecessary complications and makes your code more prone to deadlocks.

For a ReaderWriterLockSlim that allows recursion, the following can be said about the modes a thread can enter:

  • A thread in read mode can enter read mode recursively, but cannot enter write mode or upgradeable mode. If it tries to do this, a LockRecursionException is thrown. Entering read mode and then entering write mode or upgradeable mode is a pattern with a strong probability of deadlocks, so it is not allowed. As discussed earlier, upgradeable mode is provided for cases where it is necessary to upgrade a lock.

  • A thread in upgradeable mode can enter write mode and/or read mode, and can enter any of the three modes recursively. However, an attempt to enter write mode blocks if there are other threads in read mode.

  • A thread in write mode can enter read mode and/or upgradeable mode, and can enter any of the three modes recursively.

  • A thread that has not entered the lock can enter any mode. This attempt can block for the same reasons as an attempt to enter a non-recursive lock.

A thread can exit the modes it has entered in any order, as long as it exits each mode exactly as many times as it entered that mode. If a thread tries to exit a mode too many times, or to exit a mode it has not entered, a SynchronizationLockException is thrown.

Lock States

You may find it useful to think of the lock in terms of its states. A ReaderWriterLockSlim can be in one of four states: not entered, read, upgrade, and write.

  • Not entered: In this state, no threads have entered the lock (or all threads have exited the lock).

  • Read: In this state, one or more threads have entered the lock for read access to the protected resource.

    NoteNote

    A thread can enter the lock in read mode by using the EnterReadLock or TryEnterReadLock methods, or by downgrading from upgradeable mode.

  • Upgrade: In this state, one thread has entered the lock for read access with the option to upgrade to write access (that is, in upgradeable mode), and zero or more threads have entered the lock for read access. No more than one thread at a time can enter the lock with the option to upgrade; additional threads that try to enter upgradeable mode are blocked.

  • Write: In this state, one thread has entered the lock for write access to the protected resource. That thread has exclusive possession of the lock. Any other thread that tries to enter the lock for any reason is blocked.

The following table describes the transitions between lock states, for locks that do not allow recursion, when a thread t takes the action described in the leftmost column. At the time it takes the action, t has no mode. (The special case where t is in upgradeable mode is described in the table footnotes.) The top row describes the starting state of the lock. The cells describe what happens to the thread, and show changes to the lock state in parentheses.

Not entered (N)

Read (R)

Upgrade (U)

Write (W)

t enters read mode

t enters (R).

t blocks if threads are waiting for write mode; otherwise, t enters.

t blocks if threads are waiting for write mode; otherwise, t enters.1

t blocks.

t enters upgradeable mode

t enters (U).

t blocks if threads are waiting for write mode or upgrade mode; otherwise, t enters (U).

t blocks.

t blocks.

t enters write mode

t enters (W).

t blocks.

t blocks.2

t blocks.

1 If t starts out in upgradeable mode, it enters read mode. This action never blocks. The lock state does not change. (The thread can then complete a downgrade to read mode by exiting upgradeable mode.)

2 If t starts out in upgradeable mode, it blocks if there are threads in read mode. Otherwise it upgrades to write mode. The lock state changes to Write (W). If t blocks because there are threads in read mode, it enters write mode as soon as the last thread exits read mode, even if there are threads waiting to enter write mode.

When a state change occurs because a thread exits the lock, the next thread to be awakened is selected as follows:

  • First, a thread that is waiting for write mode and is already in upgradeable mode (there can be at most one such thread).

  • Failing that, a thread that is waiting for write mode.

  • Failing that, a thread that is waiting for upgradeable mode.

  • Failing that, all threads that are waiting for read mode.

The subsequent state of the lock is always Write (W) in the first two cases and Upgrade (U) in the third case, regardless of the state of the lock when the exiting thread triggered the state change. In the last case, the state of the lock is Upgrade (U) if there is a thread in upgradeable mode after the state change, and Read (R) otherwise, regardless of the prior state.

NoteNote

The HostProtectionAttribute attribute applied to this type or member has the following Resources property value: MayLeakOnAbort | Synchronization | ExternalThreading. The HostProtectionAttribute does not affect desktop applications (which are typically started by double-clicking an icon, typing a command, or entering a URL in a browser). For more information, see the HostProtectionAttribute class or SQL Server Programming and Host Protection Attributes.

The following example shows a simple synchronized cache that holds strings with integer keys. An instance of ReaderWriterLockSlim is used to synchronize access to the Dictionary<(Of <(TKey, TValue>)>) that serves as the inner cache.

The example includes simple methods to add to the cache, delete from the cache, and read from the cache. To demonstrate time-outs, the example includes a method that adds to the cache only if it can do so within a specified time-out.

To demonstrate upgradeable mode, the example includes a method that retrieves the value associated with a key and compares it with a new value. If the value is unchanged, the method returns a status indicating no change. It no value is found for the key, the key/value pair is inserted. If the value has changed, it is updated. Upgradeable mode allows the thread to upgrade from read access to write access as needed, without the risk of deadlocks.

The example includes a nested enumeration that specifies the return values for the method that demonstrates upgradeable mode.

The example uses the default constructor to create the lock, so recursion is not allowed. Programming the ReaderWriterLockSlim is simpler and less prone to error when the lock does not allow recursion.

Visual Basic
Imports System
Imports System.Threading
Imports System.Collections.Generic

Public Class SynchronizedCache
    Private cacheLock As New ReaderWriterLockSlim()
    Private innerCache As New Dictionary(Of Integer, String)

    Public Function Read(ByVal key As Integer) As String
        cacheLock.EnterReadLock()
        Try
            Return innerCache(key)
        Finally
            cacheLock.ExitReadLock()
        End Try
    End Function

    Public Sub Add(ByVal key As Integer, ByVal value As String)
        cacheLock.EnterWriteLock()
        Try
            innerCache.Add(key, value)
        Finally
            cacheLock.ExitWriteLock()
        End Try
    End Sub

    Public Function AddWithTimeout(ByVal key As Integer, ByVal value As String, _
                                   ByVal timeout As Integer) As Boolean
        If cacheLock.TryEnterWriteLock(timeout) Then
            Try
                innerCache.Add(key, value)
            Finally
                cacheLock.ExitWriteLock()
            End Try
            Return True
        Else
            Return False
        End If
    End Function

    Public Function AddOrUpdate(ByVal key As Integer, _
                                ByVal value As String) As AddOrUpdateStatus
        cacheLock.EnterUpgradeableReadLock()
        Try
            Dim result As String = Nothing
            If innerCache.TryGetValue(key, result) Then
                If result = value Then
                    Return AddOrUpdateStatus.Unchanged
                Else
                    cacheLock.EnterWriteLock()
                    Try
                        innerCache.Item(key) = value
                    Finally
                        cacheLock.ExitWriteLock()
                    End Try
                    Return AddOrUpdateStatus.Updated
                End If
            Else
                cacheLock.EnterWriteLock()
                Try
                    innerCache.Add(key, value)
                Finally
                    cacheLock.ExitWriteLock()
                End Try
                Return AddOrUpdateStatus.Added
            End If
        Finally
            cacheLock.ExitUpgradeableReadLock()
        End Try
    End Function

    Public Sub Delete(ByVal key As Integer)
        cacheLock.EnterWriteLock()
        Try
            innerCache.Remove(key)
        Finally
            cacheLock.ExitWriteLock()
        End Try
    End Sub

    Public Enum AddOrUpdateStatus
        Added
        Updated
        Unchanged
    End Enum
End Class
C#
using System;
using System.Threading;
using System.Collections.Generic;

public class SynchronizedCache
{
    private ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();
    private Dictionary<int, string> innerCache = new Dictionary<int, string>();

    public string Read(int key)
    {
        cacheLock.EnterReadLock();
        try
        {
            return innerCache[key];
        }
        finally
        {
            cacheLock.ExitReadLock();
        }
    }

    public void Add(int key, string value)
    {
        cacheLock.EnterWriteLock();
        try
        {
            innerCache.Add(key, value);
        }
        finally
        {
            cacheLock.ExitWriteLock();
        }
    }

    public bool AddWithTimeout(int key, string value, int timeout)
    {
        if (cacheLock.TryEnterWriteLock(timeout))
        {
            try
            {
                innerCache.Add(key, value);
            }
            finally
            {
                cacheLock.ExitWriteLock();
            }
            return true;
        }
        else
        {
            return false;
        }
    }

    public AddOrUpdateStatus AddOrUpdate(int key, string value)
    {
        cacheLock.EnterUpgradeableReadLock();
        try
        {
            string result = null;
            if (innerCache.TryGetValue(key, out result))
            {
                if (result == value)
                {
                    return AddOrUpdateStatus.Unchanged;
                }
                else
                {
                    cacheLock.EnterWriteLock();
                    try
                    {
                        innerCache[key] = value;
                    }
                    finally
                    {
                        cacheLock.ExitWriteLock();
                    }
                    return AddOrUpdateStatus.Updated;
                }
            }
            else
            {
                cacheLock.EnterWriteLock();
                try
                {
                    innerCache.Add(key, value);
                }
                finally
                {
                    cacheLock.ExitWriteLock();
                }
                return AddOrUpdateStatus.Added;
            }
        }
        finally
        {
            cacheLock.ExitUpgradeableReadLock();
        }
    }

    public void Delete(int key)
    {
        cacheLock.EnterWriteLock();
        try
        {
            innerCache.Remove(key);
        }
        finally
        {
            cacheLock.ExitWriteLock();
        }
    }

    public enum AddOrUpdateStatus
    {
        Added,
        Updated,
        Unchanged
    };
}

.NET Framework

Supported in: 4, 3.5

.NET Framework Client Profile

Supported in: 4, 3.5 SP1

Windows 7, Windows Vista SP1 or later, Windows XP SP3, Windows Server 2008 (Server Core Role not supported), Windows Server 2008 R2 (Server Core Role not supported), Windows Server 2003 SP2

The .NET Framework does not support all versions of every platform. For a list of the supported versions, see .NET Framework System Requirements.

This type is thread safe.

Biblioteca de clases de .NET Framework
ReaderWriterLockSlim (Clase)

Representa un bloqueo que se utiliza para administrar el acceso a un recurso y que permite varios subprocesos para la lectura o acceso exclusivo para la escritura.

System..::.Object
  System.Threading..::.ReaderWriterLockSlim

Espacio de nombres:  System.Threading
Ensamblado:  System.Core (en System.Core.dll)
Visual Basic
<HostProtectionAttribute(SecurityAction.LinkDemand, MayLeakOnAbort := True)> _
<HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization := True,  _
    ExternalThreading := True)> _
Public Class ReaderWriterLockSlim _
    Implements IDisposable
C#
[HostProtectionAttribute(SecurityAction.LinkDemand, MayLeakOnAbort = true)]
[HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization = true, 
    ExternalThreading = true)]
public class ReaderWriterLockSlim : IDisposable
Visual C++
[HostProtectionAttribute(SecurityAction::LinkDemand, MayLeakOnAbort = true)]
[HostProtectionAttribute(SecurityAction::LinkDemand, Synchronization = true, 
    ExternalThreading = true)]
public ref class ReaderWriterLockSlim : IDisposable
F#
[<HostProtectionAttribute(SecurityAction.LinkDemand, MayLeakOnAbort = true)>]
[<HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization = true, 
    ExternalThreading = true)>]
type ReaderWriterLockSlim =  
    class
        interface IDisposable
    end

El tipo ReaderWriterLockSlim expone los siguientes miembros.

  NombreDescripción
Método públicoReaderWriterLockSlim()()()Inicializa una nueva instancia de la clase ReaderWriterLockSlim con los valores de propiedad predeterminados.
Método públicoReaderWriterLockSlim(LockRecursionPolicy)Inicializa una nueva instancia de la clase ReaderWriterLockSlim especificando la directiva de recursividad de bloqueo.
Arriba
  NombreDescripción
Propiedad públicaCurrentReadCountObtiene el número total de subprocesos únicos que han entrado en el bloqueo en modo de lectura.
Propiedad públicaIsReadLockHeldObtiene un valor que indica si el subproceso actual ha entrado en el bloqueo en modo de lectura.
Propiedad públicaIsUpgradeableReadLockHeldObtiene un valor que indica si el subproceso actual ha entrado en el bloqueo en modo de actualización.
Propiedad públicaIsWriteLockHeldObtiene un valor que indica si el subproceso actual ha entrado en el bloqueo en modo de escritura.
Propiedad públicaRecursionPolicyObtiene un valor que indica la directiva de recursividad del objeto ReaderWriterLockSlim actual.
Propiedad públicaRecursiveReadCountObtiene el número de veces que el subproceso actual ha entrado en el bloqueo en modo de lectura, como una indicación de recursividad.
Propiedad públicaRecursiveUpgradeCountObtiene el número de veces que el subproceso actual ha entrado en el bloqueo en modo de actualización, como una indicación de recursividad.
Propiedad públicaRecursiveWriteCountObtiene el número de veces que el subproceso actual ha entrado en el bloqueo en modo de escritura, como una indicación de recursividad.
Propiedad públicaWaitingReadCountObtiene el número total de subprocesos que están a la espera de entrar en el bloqueo en modo de lectura.
Propiedad públicaWaitingUpgradeCountObtiene el número total de subprocesos que están a la espera de entrar en el bloqueo en modo de actualización.
Propiedad públicaWaitingWriteCountObtiene el número total de subprocesos que están a la espera de entrar en el bloqueo en modo de escritura.
Arriba
  NombreDescripción
Método públicoDisposeLibera todos los recursos utilizados por la instancia actual de la clase ReaderWriterLockSlim.
Método públicoEnterReadLockIntenta entrar en el bloqueo en modo de lectura.
Método públicoEnterUpgradeableReadLockIntenta entrar en el bloqueo en modo de actualización.
Método públicoEnterWriteLockIntenta entrar en el bloqueo en modo de escritura.
Método públicoEquals(Object)Determina si el objeto Object especificado es igual al objeto Object actual. (Se hereda de Object).
Método públicoExitReadLockReduce el recuento de recursividad para el modo de lectura y sale del modo de lectura si el recuento resultante es 0 (cero).
Método públicoExitUpgradeableReadLockReduce el recuento de recursividad para el modo de actualización y sale del modo de actualización si el recuento resultante es 0 (cero).
Método públicoExitWriteLockReduce el recuento de recursividad para el modo de escritura y sale del modo de escritura si el recuento resultante es 0 (cero).
Método protegidoFinalizePermite que un objeto intente liberar recursos y realizar otras operaciones de limpieza antes de ser reclamado por la recolección de elementos no utilizados. (Se hereda de Object).
Método públicoGetHashCodeActúa como función hash para un tipo concreto. (Se hereda de Object).
Método públicoGetTypeObtiene el objeto Type de la instancia actual. (Se hereda de Object).
Método protegidoMemberwiseCloneCrea una copia superficial del objeto Object actual. (Se hereda de Object).
Método públicoToStringDevuelve una cadena que representa el objeto actual. (Se hereda de Object).
Método públicoTryEnterReadLock(Int32)Intenta entrar en el bloqueo en modo de lectura, con un tiempo de espera entero opcional.
Método públicoTryEnterReadLock(TimeSpan)Intenta entrar en el bloqueo en modo de lectura, con tiempo de espera opcional.
Método públicoTryEnterUpgradeableReadLock(Int32)Intenta entrar en el bloqueo en modo de actualización, con tiempo de espera opcional.
Método públicoTryEnterUpgradeableReadLock(TimeSpan)Intenta entrar en el bloqueo en modo de actualización, con tiempo de espera opcional.
Método públicoTryEnterWriteLock(Int32)Intenta entrar en el bloqueo en modo de escritura, con tiempo de espera opcional.
Método públicoTryEnterWriteLock(TimeSpan)Intenta entrar en el bloqueo en modo de escritura, con tiempo de espera opcional.
Arriba

Utilice ReaderWriterLockSlim para proteger un recurso que leen varios subprocesos y en el que escribe un solo subproceso a la vez. ReaderWriterLockSlim permite que varios subprocesos estén en modo de lectura, permite que un subproceso esté en modo de escritura con propiedad exclusiva del bloqueo y permite que un subproceso que tiene acceso de lectura esté en modo de lectura actualizable, modo desde el cual puede actualizarse a modo de escritura sin tener que abandonar su acceso de lectura al recurso.

NotaNota

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. ReaderWriterLockSlim se recomienda para todos los trabajos de desarrollo nuevos.

De forma predeterminada, las nuevas instancias de ReaderWriterLockSlim se crean con el marcador LockRecursionPolicy..::.NoRecursion y no permiten la recursividad. Esta directiva predeterminada se recomienda para todos los trabajos de desarrollo nuevos, porque la recursividad presenta complicaciones innecesarias y hace que el código sea más susceptible a los interbloqueos. Para simplificar la migración de los proyectos existentes que utilizan Monitor o ReaderWriterLock, puede usar el marcador LockRecursionPolicy..::.SupportsRecursion para crear instancias de ReaderWriterLockSlim que permitan la recursividad.

Un subproceso puede entrar en el bloqueo en tres modos: modo de lectura, modo de escritura y modo de lectura actualizable (en el resto de este tema, "modo de lectura actualizable" se denomina "modo de actualización" y se prefiere la frase "entrar en modo de x" a "entrar en el bloqueo en modo de x, que es más larga).

Independientemente de la directiva de recursividad, sólo puede haber un subproceso en modo de escritura en un momento dado. Cuando un subproceso está en modo de escritura, ningún otro subproceso puede entrar en el bloqueo, en ningún modo. Sólo puede haber un subproceso en modo de actualización en un momento dado. Puede haber un número ilimitado de subprocesos en modo de lectura, y puede haber un subproceso en modo de actualización mientras otros están en modo de lectura.

ReaderWriterLockSlim es afín a los subprocesos administrados; es decir, cada objeto Thread debe realizar sus propias llamadas al método para entrar en los modos de bloqueo y salir de ellos. Ningún subproceso puede cambiar el modo de otro subproceso.

Si ReaderWriterLockSlim no permite la recursividad, un subproceso que intenta entrar en el bloqueo se puede bloquear por varias razones:

  • Un subproceso que intenta entrar en modo de lectura se bloquea si hay subprocesos a la espera de entrar en modo de escritura o si hay un solo subproceso en modo de escritura.

    NotaNota

    El bloqueo de nuevos lectores cuando hay escritores en la cola es una directiva de equidad de bloqueo que favorece a los escritores. La directiva de equidad actual equilibra la equidad para lectores y escritores, con el fin de mejorar el rendimiento en los escenarios más comunes. En futuras versiones de .NET Framework quizás se incluyan nuevas directivas de equidad.

  • Un subproceso que intenta entrar en modo de actualización se bloquea si ya es un subproceso en modo de actualización, si hay subprocesos a la espera de entrar en modo de escritura o si hay un solo subproceso en modo de escritura.

  • Un subproceso que intenta entrar en modo de escritura se bloquea si hay un subproceso en cualquiera de los tres modos.

Actualizar y degradar bloqueos

El modo de actualización está pensado para los casos en los que un subproceso normalmente lee el recurso protegido, pero podría necesitar escribir en él si se cumple alguna condición. Un subproceso que ha entrado en ReaderWriterLockSlim en modo de actualización tiene acceso de lectura al recurso protegido y puede actualizarse al modo de escritura mediante una llamada al método EnterWriteLock o TryEnterWriteLock. Dado que no puede haber más de un subproceso en modo de actualización a la vez, la actualización al modo de escritura no puede producir un interbloqueo cuando no se permite la recursividad, que es la directiva predeterminada.

Nota importanteImportante

Con independencia de la directiva de recursividad, un subproceso que entró inicialmente en modo de lectura no puede actualizarse a modo de actualización o a modo de escritura, porque ese modelo genera una probabilidad grande de interbloqueos. Por ejemplo, si dos subprocesos que se encuentran en modo de lectura intentan entrar en modo de escritura, se interbloquean. El modo de actualización está diseñado para evitar estos interbloqueos.

Si hay otros subprocesos en modo de lectura, el subproceso que se está actualizando se bloquea. Mientras se bloquea el subproceso, se bloquearán otros subprocesos que intenten entrar en modo de lectura. Cuando todos los subprocesos han salido del modo de lectura, el subproceso actualizable bloqueado entra en modo de escritura. Si hay otros subprocesos a la espera de entrar en modo de escritura, siguen bloqueados, porque el subproceso que está en modo de actualización evita que obtengan acceso exclusivo al recurso.

Cuando el subproceso en modo de actualización sale del modo de escritura, pueden entrar en modo de lectura otros subprocesos que estén a la espera de tal acción, a menos que haya subprocesos a la espera de entrar en modo de escritura. El subproceso en modo de actualización puede actualizarse y degradarse indefinidamente, siempre y cuando sea el único subproceso que escribe en el recurso protegido.

Nota importanteImportante

Si permite que varios subprocesos entren en modo de escritura o en modo de actualización, no debe permitir que un subproceso monopolice el modo de actualización. De lo contrario, los subprocesos que intenten entrar directamente en modo de escritura se bloquearán indefinidamente y, mientras estén bloqueados, otros subprocesos no podrán entrar en modo de lectura.

Un subproceso en modo de actualización puede degradarse a modo de lectura llamando primero al método EnterReadLock y después al método ExitUpgradeableReadLock. Este modelo de degradación se permite para todas las directivas de recursividad de bloqueo, incluso NoRecursion.

Después de degradarse a modo de lectura, un subproceso no puede volver a entrar en modo de actualización hasta que haya salido del modo de lectura.

Entrar en el bloqueo de forma recursiva

Puede crear un ReaderWriterLockSlim que admita la entrada recursiva en el bloqueo utilizando el constructor ReaderWriterLockSlim(LockRecursionPolicy) que especifica la directiva de bloqueo y especificando LockRecursionPolicy..::.SupportsRecursion.

NotaNota

El uso de la recursividad no se recomienda para los trabajos de desarrollo nuevos, porque presenta complicaciones innecesarias y hace que el código sea más susceptible a los interbloqueos.

Para un objeto ReaderWriterLockSlim que permite la recursividad se puede comentar lo siguiente acerca de los modos en los que puede entrar un subproceso:

  • Un subproceso en modo de lectura puede entrar en modo de lectura de forma recursiva, pero no puede entrar en modo de escritura ni en modo de actualización. Si lo intenta, se inicia LockRecursionException. Entrar en modo de lectura y después en modo de escritura o actualización es un modelo con muchas probabilidades de interbloqueos, por lo que no se permite. Como se ha mencionado anteriormente, el modo de actualización se proporciona para los casos en que es necesario actualizar un bloqueo.

  • Un subproceso en modo de actualización puede entrar en modo de escritura y/o modo de lectura y puede entrar de forma recursiva en cualquiera de los tres modos. Sin embargo, al intentar entrar en modo de escritura, se produce un bloqueo si hay otros subprocesos en modo de lectura.

  • Un subproceso en modo de escritura puede entrar en modo de lectura y/o en modo de actualización y puede entrar de forma recursiva en cualquiera de los tres modos.

  • Un subproceso que no ha entrado en el bloqueo puede entrar en cualquier modo. Este intento puede producir un bloqueo por las mismas razones que un intento de entrar en un bloqueo no recursivo.

Un subproceso puede salir de los modos en los que ha entrado en cualquier orden, siempre que salga de cada modo exactamente el mismo número de veces que ha entrado. Si un subproceso intenta salir de un modo demasiadas veces o salir de un modo en el que no ha entrado, se inicia SynchronizationLockException.

Estados de bloqueo

Puede que le resulte útil considerar el bloqueo en términos de sus estados. Un ReaderWriterLockSlim puede estar en uno de cuatro estados: no entrado, lectura, actualización y escritura.

  • No entrado: en este estado, ningún subproceso ha entrado en el bloqueo (o todos los subprocesos han salido del mismo).

  • Lectura: en este estado, uno o más subprocesos han entrado en el bloqueo para tener acceso de lectura al recurso protegido.

    NotaNota

    Un subproceso puede entrar en el bloqueo en modo de lectura a través del método EnterReadLock o TryEnterReadLock o degradándose desde el modo de actualización.

  • Actualización: en este estado, un subproceso ha entrado en el bloqueo para tener acceso de lectura con la opción de actualizarse a acceso de escritura (es decir, en modo de actualización) y cero o más subprocesos han entrado en el bloqueo para tener acceso de lectura. Sólo un subproceso puede entrar en el bloqueo con la opción de actualización; los demás bloqueos que intenten entrar en modo de actualización se bloquean.

  • Escritura: en este estado, un subproceso ha entrado en el bloqueo para tener acceso de escritura al recurso protegido. Ese subproceso tiene posesión exclusiva del bloqueo. Los demás subprocesos que intenten entrar en el bloqueo por cualquier razón se bloquearán.

En la tabla siguiente se describen las transiciones entre los estados de bloqueo, para los bloqueos que no permiten la recursividad, cuando un subproceso t realiza la acción descrita en la columna situada en el extremo izquierdo. Cuando realiza la acción, t no tiene ningún modo (cuando t está en modo de actualización, se describe en las notas al pie de la tabla, ya que es un caso especial). La fila superior describe el estado inicial del bloqueo. Las celdas describen lo que le sucede al subproceso y muestran los cambios del estado de bloqueo entre paréntesis.

No entrado (N)

Lectura (L)

Actualización (A)

Escritura (E)

t entra en modo de lectura

t entra en (L).

t se bloquea si hay subprocesos a la espera del modo de escritura; de lo contrario, t entra.

t se bloquea si hay subprocesos a la espera del modo de escritura; de lo contrario, t entra.1

t se bloquea.

t entra en modo de actualización

t entra en (A).

t se bloquea si hay subprocesos a la espera del modo de escritura o de actualización; de lo contrario, t entra en (A).

t se bloquea.

t se bloquea.

t entra en modo de escritura

t entra en (E).

t se bloquea.

t se bloquea.2

t se bloquea.

1 Si t empieza en modo de actualización, entra en modo de lectura. Esta acción nunca se bloquea. El estado del bloqueo no cambia (después, el subproceso puede completar una degradación a modo de lectura saliendo del modo de actualización).

2 Si t empieza en modo de actualización, se bloquea si hay subprocesos en modo de lectura. De lo contrario, se actualiza a modo de escritura. El estado del bloqueo cambia a Escritura (E). Si t se bloquea porque hay subprocesos en modo de lectura, entra en modo de escritura en cuanto el último subproceso salga del modo de lectura, aun cuando haya subprocesos que estén a la espera de entrar en modo de escritura.

Cuando se produce un cambio de estado porque un subproceso sale del bloqueo, el siguiente subproceso que debe activarse se selecciona de esta manera:

  • Primero, un subproceso que esté a la espera del modo de escritura y ya se encuentre en modo de actualización (puede haber como máximo un subproceso de este tipo).

  • Si no es posible, un subproceso que esté a la espera del modo de escritura.

  • Si no es posible, un subproceso que esté a la espera del modo de actualización.

  • Si no es posible, todos los subprocesos que estén a la espera del modo de lectura.

El estado posterior del bloqueo siempre es Escritura (E) en los dos primeros casos y Actualización (A) en el tercero, independientemente del estado del bloqueo cuando el subproceso que sale activa el cambio de estado. En el último caso, el estado del bloqueo es Actualización (A) si hay un subproceso en modo de actualización después del cambio de estado y Lectura (L) en los demás casos, con independencia del estado anterior.

NotaNota

El atributo HostProtectionAttribute aplicado a este tipo o miembro tiene el siguiente valor de la propiedad Resources: MayLeakOnAbort | 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.

En el ejemplo siguiente se muestra una memoria caché sincronizada simple que contiene cadenas con claves de enteros. Se usa una instancia de ReaderWriterLockSlim para sincronizar el acceso al Dictionary<(Of <(TKey, TValue>)>) que actúa como caché interna.

En el ejemplo se incluyen métodos simples para agregar, eliminar y leer información en la caché. Para mostrar los tiempos de espera, el ejemplo incluye un método que sólo agrega información a la caché si puede hacerlo dentro de un tiempo de espera especificado.

Para mostrar el modo de actualización, el ejemplo incluye un método que recupera el valor asociado a una clave y lo compara con un nuevo valor. Si el valor no cambia, el método devuelve un estado que indica que no hay cambios. Si no se encuentran valores para la clave, se inserta el par de clave y valor. Si ha cambiado el valor, se actualiza. El modo de actualización permite al subproceso actualizarse del acceso de lectura al acceso de escritura según sea necesario sin el riesgo de interbloqueos.

El ejemplo incluye una enumeración anidada que especifica los valores devueltos para el método que muestra el modo de actualización.

En el ejemplo, se usa el constructor predeterminado para crear el bloqueo; por tanto, no se permite la recursividad. Programar el objeto ReaderWriterLockSlim es más sencillo y menos propenso a errores cuando el bloqueo no permite la recursividad.

Visual Basic
Imports System
Imports System.Threading
Imports System.Collections.Generic

Public Class SynchronizedCache
    Private cacheLock As New ReaderWriterLockSlim()
    Private innerCache As New Dictionary(Of Integer, String)

    Public Function Read(ByVal key As Integer) As String
        cacheLock.EnterReadLock()
        Try
            Return innerCache(key)
        Finally
            cacheLock.ExitReadLock()
        End Try
    End Function

    Public Sub Add(ByVal key As Integer, ByVal value As String)
        cacheLock.EnterWriteLock()
        Try
            innerCache.Add(key, value)
        Finally
            cacheLock.ExitWriteLock()
        End Try
    End Sub

    Public Function AddWithTimeout(ByVal key As Integer, ByVal value As String, _
                                   ByVal timeout As Integer) As Boolean
        If cacheLock.TryEnterWriteLock(timeout) Then
            Try
                innerCache.Add(key, value)
            Finally
                cacheLock.ExitWriteLock()
            End Try
            Return True
        Else
            Return False
        End If
    End Function

    Public Function AddOrUpdate(ByVal key As Integer, _
                                ByVal value As String) As AddOrUpdateStatus
        cacheLock.EnterUpgradeableReadLock()
        Try
            Dim result As String = Nothing
            If innerCache.TryGetValue(key, result) Then
                If result = value Then
                    Return AddOrUpdateStatus.Unchanged
                Else
                    cacheLock.EnterWriteLock()
                    Try
                        innerCache.Item(key) = value
                    Finally
                        cacheLock.ExitWriteLock()
                    End Try
                    Return AddOrUpdateStatus.Updated
                End If
            Else
                cacheLock.EnterWriteLock()
                Try
                    innerCache.Add(key, value)
                Finally
                    cacheLock.ExitWriteLock()
                End Try
                Return AddOrUpdateStatus.Added
            End If
        Finally
            cacheLock.ExitUpgradeableReadLock()
        End Try
    End Function

    Public Sub Delete(ByVal key As Integer)
        cacheLock.EnterWriteLock()
        Try
            innerCache.Remove(key)
        Finally
            cacheLock.ExitWriteLock()
        End Try
    End Sub

    Public Enum AddOrUpdateStatus
        Added
        Updated
        Unchanged
    End Enum
End Class
C#
using System;
using System.Threading;
using System.Collections.Generic;

public class SynchronizedCache
{
    private ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();
    private Dictionary<int, string> innerCache = new Dictionary<int, string>();

    public string Read(int key)
    {
        cacheLock.EnterReadLock();
        try
        {
            return innerCache[key];
        }
        finally
        {
            cacheLock.ExitReadLock();
        }
    }

    public void Add(int key, string value)
    {
        cacheLock.EnterWriteLock();
        try
        {
            innerCache.Add(key, value);
        }
        finally
        {
            cacheLock.ExitWriteLock();
        }
    }

    public bool AddWithTimeout(int key, string value, int timeout)
    {
        if (cacheLock.TryEnterWriteLock(timeout))
        {
            try
            {
                innerCache.Add(key, value);
            }
            finally
            {
                cacheLock.ExitWriteLock();
            }
            return true;
        }
        else
        {
            return false;
        }
    }

    public AddOrUpdateStatus AddOrUpdate(int key, string value)
    {
        cacheLock.EnterUpgradeableReadLock();
        try
        {
            string result = null;
            if (innerCache.TryGetValue(key, out result))
            {
                if (result == value)
                {
                    return AddOrUpdateStatus.Unchanged;
                }
                else
                {
                    cacheLock.EnterWriteLock();
                    try
                    {
                        innerCache[key] = value;
                    }
                    finally
                    {
                        cacheLock.ExitWriteLock();
                    }
                    return AddOrUpdateStatus.Updated;
                }
            }
            else
            {
                cacheLock.EnterWriteLock();
                try
                {
                    innerCache.Add(key, value);
                }
                finally
                {
                    cacheLock.ExitWriteLock();
                }
                return AddOrUpdateStatus.Added;
            }
        }
        finally
        {
            cacheLock.ExitUpgradeableReadLock();
        }
    }

    public void Delete(int key)
    {
        cacheLock.EnterWriteLock();
        try
        {
            innerCache.Remove(key);
        }
        finally
        {
            cacheLock.ExitWriteLock();
        }
    }

    public enum AddOrUpdateStatus
    {
        Added,
        Updated,
        Unchanged
    };
}

.NET Framework

Compatible con: 4, 3.5

.NET Framework Client Profile

Compatible con: 4, 3.5 SP1

Windows 7, Windows Vista SP1 o posterior, Windows XP SP3, Windows Server 2008 (no se admite Server Core), Windows Server 2008 R2 (se admite Server Core con SP1 o posterior), Windows Server 2003 SP2

.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.

Contenido de la comunidad   ¿Qué es Community Content?
Agregar contenido nuevo RSS  Anotaciones
Processing
© 2012 Microsoft. Reservados todos los derechos. Temas legales | Marcas Registradas | Declaración de privacidad
Page view tracker