ReaderWriterLockSlim Classe

Definição

Representa um bloqueio que é usado para gerenciar o acesso a um recurso, permitindo vários threads para leitura ou acesso exclusivo para gravação.Represents a lock that is used to manage access to a resource, allowing multiple threads for reading or exclusive access for writing.

public ref class ReaderWriterLockSlim : IDisposable
public class ReaderWriterLockSlim : IDisposable
type ReaderWriterLockSlim = class
    interface IDisposable
Public Class ReaderWriterLockSlim
Implements IDisposable
Herança
ReaderWriterLockSlim
Implementações

Exemplos

O exemplo a seguir mostra um cache sincronizado simples que contém cadeias de caracteres com chaves de inteiro.The following example shows a simple synchronized cache that holds strings with integer keys. Uma instância do ReaderWriterLockSlim é usada para sincronizar o acesso ao Dictionary<TKey,TValue> que funciona como o cache interno.An instance of ReaderWriterLockSlim is used to synchronize access to the Dictionary<TKey,TValue> that serves as the inner cache.

O exemplo inclui métodos simples para adicionar ao cache, excluir do cache e ler do cache.The example includes simple methods to add to the cache, delete from the cache, and read from the cache. Para demonstrar tempos limite, o exemplo incluirá um método que será adicionado ao cache somente se ele puder fazê-lo dentro de um tempo limite especificado.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.

Para demonstrar o modo atualizável, o exemplo inclui um método que recupera o valor associado a uma chave e o compara com um novo valor.To demonstrate upgradeable mode, the example includes a method that retrieves the value associated with a key and compares it with a new value. Se o valor for inalterado, o método retornará um status indicando que não há alteração.If the value is unchanged, the method returns a status indicating no change. Se nenhum valor for encontrado para a chave, o par chave/valor será inserido.If no value is found for the key, the key/value pair is inserted. Se o valor tiver sido alterado, ele será atualizado.If the value has changed, it is updated. O modo atualizável permite que o thread atualize o acesso de leitura para acesso de gravação conforme necessário, sem o risco de deadlocks.Upgradeable mode allows the thread to upgrade from read access to write access as needed, without the risk of deadlocks.

O exemplo inclui uma enumeração aninhada que especifica os valores de retorno para o método que demonstra o modo atualizável.The example includes a nested enumeration that specifies the return values for the method that demonstrates upgradeable mode.

O exemplo usa o construtor sem parâmetros para criar o bloqueio, portanto, a recursão não é permitida.The example uses the parameterless constructor to create the lock, so recursion is not allowed. A programação do ReaderWriterLockSlim é mais simples e menos propenso a erros quando o bloqueio não permite recursão.Programming the ReaderWriterLockSlim is simpler and less prone to error when the lock does not allow recursion.

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
Imports System.Collections.Generic
Imports System.Threading
Imports System.Threading.Tasks

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

    public int Count
    { get { return innerCache.Count; } }

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

    ~SynchronizedCache()
    {
       if (cacheLock != null) cacheLock.Dispose();
    }
}
Public Class SynchronizedCache
    Private cacheLock As New ReaderWriterLockSlim()
    Private innerCache As New Dictionary(Of Integer, String)

    Public ReadOnly Property Count As Integer
       Get
          Return innerCache.Count
       End Get
    End Property
    
    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

    Protected Overrides Sub Finalize()
       If cacheLock IsNot Nothing Then cacheLock.Dispose()
    End Sub
End Class

O código a seguir usa o SynchronizedCache objeto para armazenar um dicionário de nomes legume.The following code then uses the SynchronizedCache object to store a dictionary of vegetable names. Ele cria três tarefas.It creates three tasks. O primeiro grava os nomes dos esistos armazenados em uma matriz em uma SynchronizedCache instância.The first writes the names of vegetables stored in an array to a SynchronizedCache instance. A segunda e a terceira tarefa exibem os nomes das fracas, a primeira em ordem crescente (de índice baixo para alto índice), a segunda em ordem decrescente.The second and third task display the names of the vegetables, the first in ascending order (from low index to high index), the second in descending order. A tarefa final procura a cadeia de caracteres "pepino" e, ao encontrá-la, chama o EnterUpgradeableReadLock método para substituir a cadeia de caracteres "Bean verde".The final task searches for the string "cucumber" and, when it finds it, calls the EnterUpgradeableReadLock method to substitute the string "green bean".

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
Imports System.Collections.Generic
Imports System.Threading
Imports System.Threading.Tasks

public class Example
{
   public static void Main()
   {
      var sc = new SynchronizedCache();
      var tasks = new List<Task>();
      int itemsWritten = 0;

      // Execute a writer.
      tasks.Add(Task.Run( () => { String[] vegetables = { "broccoli", "cauliflower",
                                                          "carrot", "sorrel", "baby turnip",
                                                          "beet", "brussel sprout",
                                                          "cabbage", "plantain",
                                                          "spinach", "grape leaves",
                                                          "lime leaves", "corn",
                                                          "radish", "cucumber",
                                                          "raddichio", "lima beans" };
                                  for (int ctr = 1; ctr <= vegetables.Length; ctr++)
                                     sc.Add(ctr, vegetables[ctr - 1]);

                                  itemsWritten = vegetables.Length;
                                  Console.WriteLine("Task {0} wrote {1} items\n",
                                                    Task.CurrentId, itemsWritten);
                                } ));
      // Execute two readers, one to read from first to last and the second from last to first.
      for (int ctr = 0; ctr <= 1; ctr++) {
         bool desc = Convert.ToBoolean(ctr);
         tasks.Add(Task.Run( () => { int start, last, step;
                                     int items;
                                     do {
                                        String output = String.Empty;
                                        items = sc.Count;
                                        if (! desc) {
                                           start = 1;
                                           step = 1;
                                           last = items;
                                        }
                                        else {
                                           start = items;
                                           step = -1;
                                           last = 1;
                                        }

                                        for (int index = start; desc ? index >= last : index <= last; index += step)
                                           output += String.Format("[{0}] ", sc.Read(index));

                                        Console.WriteLine("Task {0} read {1} items: {2}\n",
                                                          Task.CurrentId, items, output);
                                     } while (items < itemsWritten | itemsWritten == 0);
                             } ));
      }
      // Execute a red/update task.
      tasks.Add(Task.Run( () => { Thread.Sleep(100);
                                  for (int ctr = 1; ctr <= sc.Count; ctr++) {
                                     String value = sc.Read(ctr);
                                     if (value == "cucumber")
                                        if (sc.AddOrUpdate(ctr, "green bean") != SynchronizedCache.AddOrUpdateStatus.Unchanged)
                                           Console.WriteLine("Changed 'cucumber' to 'green bean'");
                                  }
                                } ));

      // Wait for all three tasks to complete.
      Task.WaitAll(tasks.ToArray());

      // Display the final contents of the cache.
      Console.WriteLine();
      Console.WriteLine("Values in synchronized cache: ");
      for (int ctr = 1; ctr <= sc.Count; ctr++)
         Console.WriteLine("   {0}: {1}", ctr, sc.Read(ctr));
   }
}
// The example displays the following output:
//    Task 1 read 0 items:
//
//    Task 3 wrote 17 items
//
//
//    Task 1 read 17 items: [broccoli] [cauliflower] [carrot] [sorrel] [baby turnip] [
//    beet] [brussel sprout] [cabbage] [plantain] [spinach] [grape leaves] [lime leave
//    s] [corn] [radish] [cucumber] [raddichio] [lima beans]
//
//    Task 2 read 0 items:
//
//    Task 2 read 17 items: [lima beans] [raddichio] [cucumber] [radish] [corn] [lime
//    leaves] [grape leaves] [spinach] [plantain] [cabbage] [brussel sprout] [beet] [b
//    aby turnip] [sorrel] [carrot] [cauliflower] [broccoli]
//
//    Changed 'cucumber' to 'green bean'
//
//    Values in synchronized cache:
//       1: broccoli
//       2: cauliflower
//       3: carrot
//       4: sorrel
//       5: baby turnip
//       6: beet
//       7: brussel sprout
//       8: cabbage
//       9: plantain
//       10: spinach
//       11: grape leaves
//       12: lime leaves
//       13: corn
//       14: radish
//       15: green bean
//       16: raddichio
//       17: lima beans
Public Module Example
   Public Sub Main()
      Dim sc As New SynchronizedCache()
      Dim tasks As New List(Of Task)
      Dim itemsWritten As Integer
      
      ' Execute a writer.
      tasks.Add(Task.Run( Sub()
                             Dim vegetables() As String = { "broccoli", "cauliflower",
                                                            "carrot", "sorrel", "baby turnip",
                                                            "beet", "brussel sprout",
                                                            "cabbage", "plantain",
                                                            "spinach", "grape leaves",
                                                            "lime leaves", "corn",
                                                            "radish", "cucumber",
                                                            "raddichio", "lima beans" }
                             For ctr As Integer = 1 to vegetables.Length
                                sc.Add(ctr, vegetables(ctr - 1))
                             Next
                             itemsWritten = vegetables.Length
                             Console.WriteLine("Task {0} wrote {1} items{2}",
                                               Task.CurrentId, itemsWritten, vbCrLf)
                          End Sub))
      ' Execute two readers, one to read from first to last and the second from last to first.
      For ctr As Integer = 0 To 1
         Dim flag As Integer = ctr
         tasks.Add(Task.Run( Sub()
                                Dim start, last, stp As Integer
                                Dim items As Integer
                                Do
                                   Dim output As String = String.Empty
                                   items = sc.Count
                                   If flag = 0 Then
                                      start = 1 : stp = 1 : last = items
                                   Else
                                      start = items : stp = -1 : last = 1
                                   End If
                                   For index As Integer = start To last Step stp
                                      output += String.Format("[{0}] ", sc.Read(index))
                                   Next
                                   Console.WriteLine("Task {0} read {1} items: {2}{3}",
                                                           Task.CurrentId, items, output,
                                                           vbCrLf)
                                Loop While items < itemsWritten Or itemsWritten = 0
                             End Sub))
      Next
      ' Execute a red/update task.
      tasks.Add(Task.Run( Sub()
                             For ctr As Integer = 1 To sc.Count
                                Dim value As String = sc.Read(ctr)
                                If value = "cucumber" Then
                                   If sc.AddOrUpdate(ctr, "green bean") <> SynchronizedCache.AddOrUpdateStatus.Unchanged Then
                                      Console.WriteLine("Changed 'cucumber' to 'green bean'")
                                   End If
                                End If
                             Next
                          End Sub ))

      ' Wait for all three tasks to complete.
      Task.WaitAll(tasks.ToArray())

      ' Display the final contents of the cache.
      Console.WriteLine()
      Console.WriteLine("Values in synchronized cache: ")
      For ctr As Integer = 1 To sc.Count
         Console.WriteLine("   {0}: {1}", ctr, sc.Read(ctr))
      Next
   End Sub
End Module
' The example displays output like the following:
'    Task 1 read 0 items:
'
'    Task 3 wrote 17 items
'
'    Task 1 read 17 items: [broccoli] [cauliflower] [carrot] [sorrel] [baby turnip] [
'    beet] [brussel sprout] [cabbage] [plantain] [spinach] [grape leaves] [lime leave
'    s] [corn] [radish] [cucumber] [raddichio] [lima beans]
'
'    Task 2 read 0 items:
'
'    Task 2 read 17 items: [lima beans] [raddichio] [cucumber] [radish] [corn] [lime
'    leaves] [grape leaves] [spinach] [plantain] [cabbage] [brussel sprout] [beet] [b
'    aby turnip] [sorrel] [carrot] [cauliflower] [broccoli]
'
'    Changed 'cucumber' to 'green bean'
'
'    Values in synchronized cache:
'       1: broccoli
'       2: cauliflower
'       3: carrot
'       4: sorrel
'       5: baby turnip
'       6: beet
'       7: brussel sprout
'       8: cabbage
'       9: plantain
'       10: spinach
'       11: grape leaves
'       12: lime leaves
'       13: corn
'       14: radish
'       15: green bean
'       16: raddichio
'       17: lima beans

Comentários

Use ReaderWriterLockSlim para proteger um recurso que é lido por vários threads e gravados em um thread por vez.Use ReaderWriterLockSlim to protect a resource that is read by multiple threads and written to by one thread at a time. ReaderWriterLockSlim permite que vários threads estejam no modo de leitura, permite que um thread esteja no modo de gravação com Propriedade exclusiva do bloqueio e permite que um thread que tem acesso de leitura esteja no modo de leitura atualizável, do qual o thread pode atualizar para o modo de gravação sem ter que ceder seu acesso de leitura ao recurso.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.

Observação

O ReaderWriterLockSlim é semelhante ao ReaderWriterLock, mas tem regras simplificadas para recursão e para atualização e downgrade de estado de bloqueio.ReaderWriterLockSlim is similar to ReaderWriterLock, but it has simplified rules for recursion and for upgrading and downgrading lock state. ReaderWriterLockSlim evita muitos casos potenciais de deadlock.ReaderWriterLockSlim avoids many cases of potential deadlock. Além disso, o desempenho de ReaderWriterLockSlim é significativamente melhor que o de ReaderWriterLock.In addition, the performance of ReaderWriterLockSlim is significantly better than ReaderWriterLock. O ReaderWriterLockSlim é recomendado para todos os novos desenvolvimentos.ReaderWriterLockSlim is recommended for all new development.

Por padrão, novas instâncias do ReaderWriterLockSlim são criadas com o LockRecursionPolicy.NoRecursion sinalizador e não permitem recursão.By default, new instances of ReaderWriterLockSlim are created with the LockRecursionPolicy.NoRecursion flag and do not allow recursion. Essa política padrão é recomendada para todo o novo desenvolvimento, pois a recursão apresenta complicações desnecessárias e torna seu código mais propenso a deadlocks.This default policy is recommended for all new development, because recursion introduces unnecessary complications and makes your code more prone to deadlocks. Para simplificar a migração de projetos existentes que usam Monitor ReaderWriterLock o ou o, você pode usar o LockRecursionPolicy.SupportsRecursion sinalizador para criar instâncias do ReaderWriterLockSlim que permitem recursão.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.

Um thread pode entrar no bloqueio em três modos: modo de leitura, modo de gravação e modo de leitura atualizável.A thread can enter the lock in three modes: read mode, write mode, and upgradeable read mode. (No restante deste tópico, "modo de leitura atualizável" é chamado de "modo de atualização", e a frase "modo de inserção x " é usada em preferência à frase mais longa "Insira o modo de bloqueio x ".)(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".)

Independentemente da política de recursão, somente um thread pode estar no modo de gravação a qualquer momento.Regardless of recursion policy, only one thread can be in write mode at any time. Quando um thread está no modo de gravação, nenhum outro thread pode entrar no bloqueio em nenhum modo.When a thread is in write mode, no other thread can enter the lock in any mode. Somente um thread pode estar no modo atualizável a qualquer momento.Only one thread can be in upgradeable mode at any time. Qualquer número de threads pode estar no modo de leitura e pode haver um thread no modo atualizável enquanto outros threads estão no modo de leitura.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.

Importante

Esse tipo implementa a interface IDisposable.This type implements the IDisposable interface. Quando você terminar de usar o tipo, deverá descartá-lo direta ou indiretamente.When you have finished using the type, you should dispose of it either directly or indirectly. Para descartar o tipo diretamente, chame o método Dispose dele em um bloco try/catch.To dispose of the type directly, call its Dispose method in a try/catch block. Para descartá-lo indiretamente, use um constructo de linguagem como using ( em C#) ou Using (em Visual Basic).To dispose of it indirectly, use a language construct such as using (in C#) or Using (in Visual Basic). Saiba mais na seção "Como usar um objeto que implementa IDisposable" no tópico da interface IDisposable.For more information, see the "Using an Object that Implements IDisposable" section in the IDisposable interface topic.

ReaderWriterLockSlim tem afinidade de thread gerenciada; ou seja, cada Thread objeto deve fazer suas próprias chamadas de método para inserir e sair dos modos de bloqueio.ReaderWriterLockSlim has managed thread affinity; that is, each Thread object must make its own method calls to enter and exit lock modes. Nenhum thread pode alterar o modo de outro thread.No thread can change the mode of another thread.

Se um não ReaderWriterLockSlim Permitir recursão, um thread que tenta entrar no bloqueio pode bloquear por vários motivos:If a ReaderWriterLockSlim does not allow recursion, a thread that tries to enter the lock can block for several reasons:

  • Um thread que tenta entrar no modo de leitura é bloqueado se houver threads aguardando para entrar no modo de gravação ou se houver um único thread no modo de gravação.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.

    Observação

    O bloqueio de novos leitores quando gravadores são colocados na fila é uma política de imparcialidade de bloqueio que favorece os gravadores.Blocking new readers when writers are queued is a lock fairness policy that favors writers. A política de imparcialidade atual equilibra a imparcialidade aos leitores e gravadores para promover a taxa de transferência nos cenários mais comuns.The current fairness policy balances fairness to readers and writers, to promote throughput in the most common scenarios. As versões futuras do .NET Framework.NET Framework podem introduzir novas políticas de imparcialidade.Future versions of the .NET Framework.NET Framework may introduce new fairness policies.

  • Um thread que tenta entrar em blocos de modo atualizável se já houver um thread no modo atualizável, se houver threads aguardando para entrar no modo de gravação ou se houver um único thread no modo de gravação.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.

  • Um thread que tenta entrar no modo de gravação é bloqueado se houver um thread em qualquer um dos três modos.A thread that tries to enter write mode blocks if there is a thread in any of the three modes.

Atualizando e fazendo downgrade de bloqueiosUpgrading and Downgrading Locks

O modo atualizável é destinado a casos em que um thread geralmente lê do recurso protegido, mas talvez precise gravar nele se alguma condição for atendida.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. Um thread que inseriu um ReaderWriterLockSlim no modo atualizável tem acesso de leitura ao recurso protegido e pode atualizar para o modo de gravação chamando os EnterWriteLock TryEnterWriteLock métodos ou.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. Como pode haver apenas um thread no modo atualizável de cada vez, a atualização para o modo de gravação não pode ser bloqueada quando a recursão não é permitida, que é a política padrão.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.

Importante

Independentemente da política de recursão, um thread que inicialmente entrou no modo de leitura não tem permissão para atualizar para modo de atualização ou modo de gravação, pois esse padrão cria uma probabilidade forte de deadlocks.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. Por exemplo, se dois threads no modo de leitura tentarem entrar no modo de gravação, eles serão bloqueados.For example, if two threads in read mode both try to enter write mode, they will deadlock. O modo atualizável foi projetado para evitar esses deadlocks.Upgradeable mode is designed to avoid such deadlocks.

Se houver outros threads no modo de leitura, o thread que está atualizando os blocos.If there are other threads in read mode, the thread that is upgrading blocks. Enquanto o thread é bloqueado, outros threads que tentam entrar no modo de leitura são bloqueados.While the thread is blocked, other threads that try to enter read mode are blocked. Quando todos os threads saíram do modo de leitura, o thread atualizável bloqueado entra no modo de gravação.When all threads have exited from read mode, the blocked upgradeable thread enters write mode. Se houver outros threads aguardando para entrar no modo de gravação, eles permanecerão bloqueados, pois o único thread que está no modo atualizável impede que eles obtenham acesso exclusivo ao recurso.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.

Quando o thread no modo atualizável sai do modo de gravação, outros threads que estão aguardando para entrar no modo de leitura podem fazer isso, a menos que haja threads aguardando para entrar no modo de gravação.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. O thread no modo atualizável pode fazer upgrade e downgrade indefinidamente, desde que seja o único thread que grava no recurso protegido.The thread in upgradeable mode can upgrade and downgrade indefinitely, as long as it is the only thread that writes to the protected resource.

Importante

Se você permitir que vários threads entrem no modo de gravação ou no modo atualizável, não deverá permitir que um thread monopolizasse o modo atualizável.If you allow multiple threads to enter write mode or upgradeable mode, you must not allow one thread to monopolize upgradeable mode. Caso contrário, os threads que tentarem entrar no modo de gravação diretamente serão bloqueados indefinidamente e, enquanto estiverem bloqueados, outros threads não poderão entrar no modo de leitura.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.

Um thread no modo atualizável pode fazer downgrade para o modo de leitura chamando primeiro o EnterReadLock método e, em seguida, chamando o ExitUpgradeableReadLock método.A thread in upgradeable mode can downgrade to read mode by first calling the EnterReadLock method and then calling the ExitUpgradeableReadLock method. Esse padrão de downgrade é permitido para todas as políticas de recursão de bloqueio, mesmo NoRecursion .This downgrade pattern is allowed for all lock recursion policies, even NoRecursion.

Após o downgrade para o modo de leitura, um thread não poderá entrar novamente no modo atualizável até sair do modo de leitura.After downgrading to read mode, a thread cannot reenter upgradeable mode until it has exited from read mode.

Inserindo o bloqueio recursivamenteEntering the Lock Recursively

Você pode criar um ReaderWriterLockSlim que ofereça suporte à entrada de bloqueio recursivo usando o ReaderWriterLockSlim(LockRecursionPolicy) Construtor que especifica a política de bloqueio e especificando LockRecursionPolicy.SupportsRecursion .You can create a ReaderWriterLockSlim that supports recursive lock entry by using the ReaderWriterLockSlim(LockRecursionPolicy) constructor that specifies lock policy, and specifying LockRecursionPolicy.SupportsRecursion.

Observação

O uso da recursão não é recomendado para novos desenvolvimentos, pois apresenta complicações desnecessárias e torna seu código mais propenso a deadlocks.The use of recursion is not recommended for new development, because it introduces unnecessary complications and makes your code more prone to deadlocks.

Para um ReaderWriterLockSlim que permite recursão, o seguinte pode ser dito sobre os modos que um thread pode inserir:For a ReaderWriterLockSlim that allows recursion, the following can be said about the modes a thread can enter:

  • Um thread no modo de leitura pode entrar no modo de leitura recursivamente, mas não pode entrar no modo de gravação ou no modo atualizável.A thread in read mode can enter read mode recursively, but cannot enter write mode or upgradeable mode. Se ele tentar fazer isso, um LockRecursionException será lançado.If it tries to do this, a LockRecursionException is thrown. Entrar no modo de leitura e, em seguida, inserir o modo de gravação ou o modo atualizável é um padrão com uma probabilidade forte de deadlocks, portanto, não é permitido.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. Conforme discutido anteriormente, o modo atualizável é fornecido para casos em que é necessário atualizar um bloqueio.As discussed earlier, upgradeable mode is provided for cases where it is necessary to upgrade a lock.

  • Um thread no modo atualizável pode entrar no modo de gravação e/ou no modo de leitura e pode inserir qualquer um dos três modos recursivamente.A thread in upgradeable mode can enter write mode and/or read mode, and can enter any of the three modes recursively. No entanto, uma tentativa de entrar no modo de gravação será bloqueada se houver outros threads no modo de leitura.However, an attempt to enter write mode blocks if there are other threads in read mode.

  • Um thread no modo de gravação pode entrar no modo de leitura e/ou no modo atualizável e pode inserir qualquer um dos três modos recursivamente.A thread in write mode can enter read mode and/or upgradeable mode, and can enter any of the three modes recursively.

  • Um thread que não entrou no bloqueio pode inserir qualquer modo.A thread that has not entered the lock can enter any mode. Essa tentativa pode bloquear pelos mesmos motivos de uma tentativa de inserir um bloqueio não recursivo.This attempt can block for the same reasons as an attempt to enter a non-recursive lock.

Um thread pode sair dos modos inseridos em qualquer ordem, desde que ele saia de cada modo exatamente quantas vezes tiver inserido esse modo.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. Se um thread tentar sair de um modo muitas vezes ou sair de um modo que não foi inserido, um SynchronizationLockException será lançado.If a thread tries to exit a mode too many times, or to exit a mode it has not entered, a SynchronizationLockException is thrown.

Estados de bloqueioLock States

Talvez você ache útil considerar o bloqueio em termos de seus Estados.You may find it useful to think of the lock in terms of its states. Um ReaderWriterLockSlim pode estar em um dos quatro Estados: não inserido, leitura, atualização e gravação.A ReaderWriterLockSlim can be in one of four states: not entered, read, upgrade, and write.

  • Não inserido: nesse estado, nenhum thread entrou no bloqueio (ou todos os threads saíram do bloqueio).Not entered: In this state, no threads have entered the lock (or all threads have exited the lock).

  • Leitura: nesse estado, um ou mais threads inseriram o bloqueio para acesso de leitura ao recurso protegido.Read: In this state, one or more threads have entered the lock for read access to the protected resource.

    Observação

    Um thread pode inserir o bloqueio no modo de leitura usando os EnterReadLock TryEnterReadLock métodos ou, ou fazendo downgrade do modo atualizável.A thread can enter the lock in read mode by using the EnterReadLock or TryEnterReadLock methods, or by downgrading from upgradeable mode.

  • Atualização: nesse estado, um thread entrou no bloqueio para acesso de leitura com a opção de atualizar para acesso de gravação (ou seja, no modo atualizável) e zero ou mais threads inseriram o bloqueio para acesso de leitura.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. Não mais de um thread por vez pode inserir o bloqueio com a opção de atualizar; threads adicionais que tentam entrar no modo atualizável são bloqueados.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.

  • Gravação: nesse estado, um thread entrou no bloqueio para acesso de gravação ao recurso protegido.Write: In this state, one thread has entered the lock for write access to the protected resource. Esse thread tem posse exclusiva do bloqueio.That thread has exclusive possession of the lock. Qualquer outro thread que tenta inserir o bloqueio por qualquer motivo é bloqueado.Any other thread that tries to enter the lock for any reason is blocked.

A tabela a seguir descreve as transições entre os Estados de bloqueio, para bloqueios que não permitem recursão, quando um thread t executa a ação descrita na coluna mais à esquerda.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. No momento em que a ação é executada, o t não tem nenhum modo.At the time it takes the action, t has no mode. (O caso especial em que o t está no modo atualizável é descrito nas notas de rodapé da tabela.) A linha superior descreve o estado inicial do bloqueio.(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. As células descrevem o que acontece com o thread e mostram as alterações no estado de bloqueio entre parênteses.The cells describe what happens to the thread, and show changes to the lock state in parentheses.

Não inserido (N)Not entered (N) Ler (R)Read (R) Atualização (U)Upgrade (U) Gravar (W)Write (W)
t entra no modo de leiturat enters read mode t insere (R).t enters (R). t bloqueia se os threads estão aguardando o modo de gravação; caso contrário, t entrará.t blocks if threads are waiting for write mode; otherwise, t enters. t bloqueia se os threads estão aguardando o modo de gravação; caso contrário, t entrará. 1t blocks if threads are waiting for write mode; otherwise, t enters.1 t trava.t blocks.
t entra no modo atualizávelt enters upgradeable mode t insere (U).t enters (U). t bloqueia se os threads estão aguardando o modo de gravação ou o modo de atualização; caso contrário, t insira (U).t blocks if threads are waiting for write mode or upgrade mode; otherwise, t enters (U). t trava.t blocks. t trava.t blocks.
t entra no modo de gravaçãot enters write mode t insere (W).t enters (W). t trava.t blocks. t trava. 2t blocks.2 t trava.t blocks.

1 se o t Iniciar no modo de atualização, ele entrará no modo de leitura.1 If t starts out in upgradeable mode, it enters read mode. Essa ação nunca é bloqueada.This action never blocks. O estado de bloqueio não é alterado.The lock state does not change. (O thread pode concluir um downgrade para o modo de leitura saindo do modo atualizável.)(The thread can then complete a downgrade to read mode by exiting upgradeable mode.)

2 se o t for iniciado no modo atualizável, ele bloqueará se houver threads no modo de leitura.2 If t starts out in upgradeable mode, it blocks if there are threads in read mode. Caso contrário, ele atualiza para o modo de gravação.Otherwise it upgrades to write mode. O estado de bloqueio muda para gravação (W).The lock state changes to Write (W). Se t os blocos tiverem threads no modo de leitura, ele entrará no modo de gravação assim que o último thread sair do modo de leitura, mesmo se houver threads aguardando para entrar no modo de gravação.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.

Quando ocorre uma alteração de estado porque um thread sai do bloqueio, o próximo thread a ser ativado é selecionado da seguinte maneira:When a state change occurs because a thread exits the lock, the next thread to be awakened is selected as follows:

  • Primeiro, um thread que está aguardando o modo de gravação e já está no modo atualizável (pode haver no máximo um desses threads).First, a thread that is waiting for write mode and is already in upgradeable mode (there can be at most one such thread).

  • Falhando, um thread que está aguardando o modo de gravação.Failing that, a thread that is waiting for write mode.

  • Falhando, um thread que está aguardando o modo atualizável.Failing that, a thread that is waiting for upgradeable mode.

  • Com falha, todos os threads que estão aguardando o modo de leitura.Failing that, all threads that are waiting for read mode.

O estado subsequente do bloqueio é sempre Write (W) nos dois primeiros casos e upgrade (U) no terceiro caso, independentemente do estado do bloqueio quando o thread existente disparava a alteração de estado.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. No último caso, o estado do bloqueio será upgrade (U) se houver um thread no modo atualizável após a alteração de estado e ler (R) caso contrário, independentemente do estado anterior.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.

Construtores

ReaderWriterLockSlim()

Inicializa uma nova instância da classe ReaderWriterLockSlim com os valores da propriedade padrão.Initializes a new instance of the ReaderWriterLockSlim class with default property values.

ReaderWriterLockSlim(LockRecursionPolicy)

Inicializa uma nova instância da classe ReaderWriterLockSlim, especificando a política de recursão de bloqueio.Initializes a new instance of the ReaderWriterLockSlim class, specifying the lock recursion policy.

Propriedades

CurrentReadCount

Obtém o número total de threads exclusivos que inseriram o bloqueio no modo de leitura.Gets the total number of unique threads that have entered the lock in read mode.

IsReadLockHeld

Obtém um valor que indica se o thread atual inseriu o bloqueio no modo de leitura.Gets a value that indicates whether the current thread has entered the lock in read mode.

IsUpgradeableReadLockHeld

Obtém um valor que indica se o thread atual inseriu o bloqueio no modo de upgrade.Gets a value that indicates whether the current thread has entered the lock in upgradeable mode.

IsWriteLockHeld

Obtém um valor que indica se o thread atual inseriu o bloqueio no modo de gravação.Gets a value that indicates whether the current thread has entered the lock in write mode.

RecursionPolicy

Obtém um valor que indica a política de recursão do objeto ReaderWriterLockSlim atual.Gets a value that indicates the recursion policy for the current ReaderWriterLockSlim object.

RecursiveReadCount

Obtém o número de vezes que o thread atual inseriu o bloqueio no modo de leitura, como uma indicação de recursão.Gets the number of times the current thread has entered the lock in read mode, as an indication of recursion.

RecursiveUpgradeCount

Obtém o número de vezes que o thread atual inseriu o bloqueio no modo de upgrade, como uma indicação de recursão.Gets the number of times the current thread has entered the lock in upgradeable mode, as an indication of recursion.

RecursiveWriteCount

Obtém o número de vezes que o thread atual inseriu o bloqueio no modo de gravação, como uma indicação de recursão.Gets the number of times the current thread has entered the lock in write mode, as an indication of recursion.

WaitingReadCount

Obtém o número total de threads que estão esperando para inserir o bloqueio no modo de leitura.Gets the total number of threads that are waiting to enter the lock in read mode.

WaitingUpgradeCount

Obtém o número total de threads que estão esperando para inserir o bloqueio no modo de upgrade.Gets the total number of threads that are waiting to enter the lock in upgradeable mode.

WaitingWriteCount

Obtém o número total de threads que estão esperando para inserir o bloqueio no modo de gravação.Gets the total number of threads that are waiting to enter the lock in write mode.

Métodos

Dispose()

Libera todos os recursos usados pela instância atual da classe ReaderWriterLockSlim.Releases all resources used by the current instance of the ReaderWriterLockSlim class.

EnterReadLock()

Tenta entrar no bloqueio em modo de leitura.Tries to enter the lock in read mode.

EnterUpgradeableReadLock()

Tenta entrar no bloqueio no modo atualizável.Tries to enter the lock in upgradeable mode.

EnterWriteLock()

Tenta entrar no bloqueio em modo de gravação.Tries to enter the lock in write mode.

Equals(Object)

Determina se o objeto especificado é igual ao objeto atual.Determines whether the specified object is equal to the current object.

(Herdado de Object)
ExitReadLock()

Reduz a contagem de recursão para o modo de leitura e sai do modo de leitura se a contagem resultante é 0 (zero).Reduces the recursion count for read mode, and exits read mode if the resulting count is 0 (zero).

ExitUpgradeableReadLock()

Reduz a contagem de recursão para o modo de upgrade e sai do modo de upgrade se a contagem resultante é 0 (zero).Reduces the recursion count for upgradeable mode, and exits upgradeable mode if the resulting count is 0 (zero).

ExitWriteLock()

Reduz a contagem de recursão para o modo de gravação e sai do modo de gravação se a contagem resultante é 0 (zero).Reduces the recursion count for write mode, and exits write mode if the resulting count is 0 (zero).

GetHashCode()

Serve como a função de hash padrão.Serves as the default hash function.

(Herdado de Object)
GetType()

Obtém o Type da instância atual.Gets the Type of the current instance.

(Herdado de Object)
MemberwiseClone()

Cria uma cópia superficial do Object atual.Creates a shallow copy of the current Object.

(Herdado de Object)
ToString()

Retorna uma cadeia de caracteres que representa o objeto atual.Returns a string that represents the current object.

(Herdado de Object)
TryEnterReadLock(Int32)

Tenta inserir o bloqueio no modo de gravação com um tempo limite inteiro opcional.Tries to enter the lock in read mode, with an optional integer time-out.

TryEnterReadLock(TimeSpan)

Tenta entrar no bloqueio no modo de leitura, com um tempo limite opcional.Tries to enter the lock in read mode, with an optional time-out.

TryEnterUpgradeableReadLock(Int32)

Tenta inserir o bloqueio no modo de upgrade, com um tempo limite opcional.Tries to enter the lock in upgradeable mode, with an optional time-out.

TryEnterUpgradeableReadLock(TimeSpan)

Tenta inserir o bloqueio no modo de upgrade, com um tempo limite opcional.Tries to enter the lock in upgradeable mode, with an optional time-out.

TryEnterWriteLock(Int32)

Tenta entrar no bloqueio no modo de gravação, com um tempo limite opcional.Tries to enter the lock in write mode, with an optional time-out.

TryEnterWriteLock(TimeSpan)

Tenta entrar no bloqueio no modo de gravação, com um tempo limite opcional.Tries to enter the lock in write mode, with an optional time-out.

Aplica-se a

Acesso thread-safe

Este tipo é thread-safe.This type is thread safe.