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

Inheritance Hierarchy
Namespace:
System.Threading
Assembly:
System.Core (in System.Core.dll)

Syntax
<HostProtectionAttribute(SecurityAction.LinkDemand, MayLeakOnAbort := True)> _
<HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization := True, _
ExternalThreading := True)> _
Public Class ReaderWriterLockSlim _
Implements IDisposable
[HostProtectionAttribute(SecurityAction.LinkDemand, MayLeakOnAbort = true)]
[HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization = true,
ExternalThreading = true)]
public class ReaderWriterLockSlim : IDisposable
[HostProtectionAttribute(SecurityAction::LinkDemand, MayLeakOnAbort = true)]
[HostProtectionAttribute(SecurityAction::LinkDemand, Synchronization = true,
ExternalThreading = true)]
public ref class ReaderWriterLockSlim : IDisposable
[<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.

Constructors

Methods

Remarks
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. Note |
|---|
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. Note |
|---|
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 LocksUpgradeable 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 |
|---|
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 |
|---|
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 RecursivelyYou can create a ReaderWriterLockSlim that supports recursive lock entry by using the ReaderWriterLockSlim(LockRecursionPolicy) constructor that specifies lock policy, and specifying LockRecursionPolicy..::.SupportsRecursion. Note |
|---|
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 StatesYou 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. 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.

Examples
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.
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
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
};
}

Version Information
.NET FrameworkSupported in: 4, 3.5 .NET Framework Client ProfileSupported in: 4, 3.5 SP1

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

Thread Safety
This type is thread safe.

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

Jerarquía de herencia
Espacio de nombres:
System.Threading
Ensamblado:
System.Core (en System.Core.dll)

Sintaxis
<HostProtectionAttribute(SecurityAction.LinkDemand, MayLeakOnAbort := True)> _
<HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization := True, _
ExternalThreading := True)> _
Public Class ReaderWriterLockSlim _
Implements IDisposable
[HostProtectionAttribute(SecurityAction.LinkDemand, MayLeakOnAbort = true)]
[HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization = true,
ExternalThreading = true)]
public class ReaderWriterLockSlim : IDisposable
[HostProtectionAttribute(SecurityAction::LinkDemand, MayLeakOnAbort = true)]
[HostProtectionAttribute(SecurityAction::LinkDemand, Synchronization = true,
ExternalThreading = true)]
public ref class ReaderWriterLockSlim : IDisposable
[<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.

Constructores

Comentarios
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. Nota |
|---|
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. Nota |
|---|
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 bloqueosEl 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. Importante |
|---|
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. Importante |
|---|
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 recursivaPuede 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. Nota |
|---|
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 bloqueoPuede 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. Nota |
|---|
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.

Ejemplos
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.
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
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
};
}

Información de versión
.NET FrameworkCompatible con: 4, 3.5 .NET Framework Client ProfileCompatible con: 4, 3.5 SP1

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

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

Vea también
|