ReaderWriterLockSlim ReaderWriterLockSlim ReaderWriterLockSlim ReaderWriterLockSlim Class

Определение

Представляет блокировку, используемую для управления доступом к ресурсу, которая позволяет нескольким потокам производить считывание или получать монопольный доступ на запись.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
Наследование
ReaderWriterLockSlimReaderWriterLockSlimReaderWriterLockSlimReaderWriterLockSlim
Реализации

Примеры

В следующем примере показано простого синхронизированного кэша, содержащего строки с целочисленных ключей.The following example shows a simple synchronized cache that holds strings with integer keys. Экземпляр ReaderWriterLockSlim используется для синхронизации доступа к Dictionary<TKey,TValue> который выступает в качестве внутреннего кэша.An instance of ReaderWriterLockSlim is used to synchronize access to the Dictionary<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. Если для ключа не найдено значение, будет вставлена данную пару ключ значение.If 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. Программирование ReaderWriterLockSlim является простым и менее подверженной ошибкам, если блокировка не допускает рекурсии.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

В следующем коде используется затем SynchronizedCache объект для сохранения словаря имен овощной.The following code then uses the SynchronizedCache object to store a dictionary of vegetable names. Он создает три задачи.It creates three tasks. Первый записывает имена овощей, хранящихся в массиве для SynchronizedCache экземпляра.The first writes the names of vegetables stored in an array to a SynchronizedCache instance. Второй и третий задачи с именами овощей, первым в порядке возрастания (от низкий индекс высокого уровня), второй в порядке убывания.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. Последняя задача осуществляет поиск строки «cucumber» и, при обнаружении ее, вызывает EnterUpgradeableReadLock способ подставить строку «зеленый bean».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

Комментарии

Используйте ReaderWriterLockSlim для защиты ресурсов, который считывается с помощью нескольких потоков и запись в один поток за раз.Use ReaderWriterLockSlim to protect a resource that is read by multiple threads and written to by one thread at a time. ReaderWriterLockSlim позволяет нескольким потокам в режиме чтения, одному потоку в режиме записи с монопольного доступа блокировки и позволяет одному потоку, который имеет доступ на чтение в обновляемом режиме чтения, из которого поток может перейти в режим записи без необходимости отказываться от его s чтения доступ к ресурсу.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.

Примечание

ReaderWriterLockSlim действует так же, как и ReaderWriterLock, но с более простыми правилами рекурсии и изменения состояния блокировки.ReaderWriterLockSlim is similar to ReaderWriterLock, but it has simplified rules for recursion and for upgrading and downgrading lock state. ReaderWriterLockSlim позволяет избежать многих ситуаций взаимоблокировки.ReaderWriterLockSlim avoids many cases of potential deadlock. Кроме того, производительность ReaderWriterLockSlim значительно выше, чем у ReaderWriterLock.In addition, the performance of ReaderWriterLockSlim is significantly better than ReaderWriterLock. Мы рекомендуем применять ReaderWriterLockSlim при любых новых разработках.ReaderWriterLockSlim is recommended for all new development.

По умолчанию новые экземпляры ReaderWriterLockSlim создаются с помощью LockRecursionPolicy.NoRecursion флаг и не допускает рекурсии.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. Чтобы упростить миграцию из существующего проекты, использующие Monitor или ReaderWriterLock, можно использовать LockRecursionPolicy.SupportsRecursion флаг для создания экземпляров ReaderWriterLockSlim , позволяющие рекурсии.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. (В остальной части этого раздела, «обновляемый режим чтения» называется «обновляемый режим» и фразу «введите x режим» используется вместо более длинной фразы «войти в блокировку в 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".)

Независимо от политики рекурсии только один поток может находиться в режиме записи в любое время.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.

Важно!

Этот тип реализует IDisposable интерфейс.This type implements the IDisposable interface. Когда вы закончите, используя тип, следует освободить его прямо или косвенно.When you have finished using the type, you should dispose of it either directly or indirectly. Чтобы удалить тип напрямую, вызовите его Dispose метод в try / catch блока.To dispose of the type directly, call its Dispose method in a try/catch block. Чтобы избавиться от его косвенно, используйте языковой конструкции, такие как using (в C#) или Using (в Visual Basic).To dispose of it indirectly, use a language construct such as using (in C#) or Using (in Visual Basic). Дополнительные сведения см. в разделе «С помощью объекта, реализует IDisposable» IDisposable разделу интерфейса.For more information, see the "Using an Object that Implements IDisposable" section in the IDisposable interface topic.

ReaderWriterLockSlim управляемые сходство потоков; то есть каждый Thread объекта необходимо вызвать функцию свой собственный метод войти и выйти из режимов блокировки.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.

Если ReaderWriterLockSlim не поддерживает рекурсии, поток можно заблокировать, пытается войти в блокировку по следующим причинам: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.

    Примечание

    Блокировка новых модулей чтения при записи помещаются в очередь — политика распределение ресурсов блокировок, дает преимущества потокам записи.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. Будущие версии .NET Framework.NET Framework может введены новые политики равноправия.Future versions of the .NET Framework.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. Поток, который ReaderWriterLockSlim в обновляемом режиме имеет доступ на чтение к защищенному ресурсу и можно перейти в режим записи путем вызова EnterWriteLock или TryEnterWriteLock методы.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.

Важно!

Независимо от политики рекурсии поток, который изначально вошел чтения режим не разрешен для обновления до обновляемый режим или режим записи, так как этот шаблон создает большую вероятность возникновения взаимоблокировок.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.

Важно!

Если разрешить нескольким потокам введите режим записи или обновляемый режим, вы не должны допускать один поток монополизировать обновляемый режим.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.

Поток в обновляемом режиме можно понизить до режима чтения путем вызова метода EnterReadLock метод и последующего вызова ExitUpgradeableReadLock метод.A thread in upgradeable mode can downgrade to read mode by first calling the EnterReadLock method and then calling the ExitUpgradeableReadLock method. Этот шаблон понижения допускается для всех политик рекурсии блокировки, даже NoRecursion.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

Можно создать ReaderWriterLockSlim , поддерживающий рекурсивная запись блокировки с помощью ReaderWriterLockSlim(LockRecursionPolicy) конструктор, который определяет политику блокировки и указав 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.

Примечание

Использование рекурсии не рекомендуется для разработки новых приложений, так как он вводит ненужные сложности и делает код вероятность возникновения взаимоблокировок.The use of recursion is not recommended for new development, because it introduces unnecessary complications and makes your code more prone to deadlocks.

Для ReaderWriterLockSlim , позволяющий рекурсии, следующие можно сказать, что о режимах, поток может войти в: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. При попытке сделать это, LockRecursionException возникает исключение.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. Если поток пытается выйти из режима слишком много раз или выйти из режима, не вошел, SynchronizationLockException возникает исключение.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. Объект ReaderWriterLockSlim может находиться в одном из четырех состояний: не указан, чтение, обновление и записи.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.

    Примечание

    Поток может войти в блокировку в режиме чтения с помощью EnterReadLock или TryEnterReadLock методов, или путем изменения уровня обслуживания обновляемый режим.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.

В следующей таблице описаны переходы между состояниями для блокировок, которые не допускают рекурсии, когда поток t действия, описанные в крайнем левом столбце.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. Во время, необходимое действие, t имеет режим без.At the time it takes the action, t has no mode. (Особого случая где t в обновляемый режим описан в сносках таблицы.) В верхней строке указано начальное состояние блокировки.(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.

Нет входов (N)Not entered (N) Read (R)Read (R) Обновления (U)Upgrade (U) Запись (W)Write (W)
t входит в режим чтенияt enters read mode t вводит (R).t enters (R). t блокируется, если потоки ожидают режим записи; в противном случае t вводит.t blocks if threads are waiting for write mode; otherwise, t enters. t блокируется, если потоки ожидают режим записи; в противном случае t вводит. 1t blocks if threads are waiting for write mode; otherwise, t enters.1 t блоки.t blocks.
t входит в обновляемый режимt enters upgradeable mode t вводит (U).t enters (U). t блокируется, если потоки ожидают режим записи или обновляемый режим; в противном случае t вводит (U).t blocks if threads are waiting for write mode or upgrade mode; otherwise, t enters (U). t блоки.t blocks. t блоки.t blocks.
t переходит в режим записиt enters write mode t вводит (W).t enters (W). t блоки.t blocks. t блоки. 2t blocks.2 t блоки.t blocks.

1 Если t запускает out в обновляемом режиме, он входит в режим чтения.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 Если t запускается в обновляемый режим, он блокируется, если существуют потоки в режиме чтения.2 If t starts out in upgradeable mode, it blocks if there are threads in read mode. В противном случае он обновляет режим записи.Otherwise it upgrades to write mode. Изменения состояния блокировки записи (W).The lock state changes to Write (W). Если t блокирует, поскольку отсутствуют потоки в режиме чтения, он переходит в режим записи как последний поток выходит из режима чтения, даже при наличии потоков, ожидающих входа в режим записи.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.

Состояние блокировки всегда находится запись (W) в первых двух случаях и обновления (U) в третьем случае, независимо от состояния блокировки, при выходе из нее потока, вызвавшего изменение состояния.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. В последнем случае состояние блокировки — обновления (U), если поток в обновляемом режиме после изменения состояния и Read (R) в противном случае, независимо от предыдущего состояния.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.

Конструкторы

ReaderWriterLockSlim() ReaderWriterLockSlim() ReaderWriterLockSlim() ReaderWriterLockSlim()

Инициализирует новый экземпляр класса ReaderWriterLockSlim значениями свойств по умолчанию.Initializes a new instance of the ReaderWriterLockSlim class with default property values.

ReaderWriterLockSlim(LockRecursionPolicy) ReaderWriterLockSlim(LockRecursionPolicy) ReaderWriterLockSlim(LockRecursionPolicy) ReaderWriterLockSlim(LockRecursionPolicy)

Инициализирует новый экземпляр класса ReaderWriterLockSlim с указанием политики рекурсии блокировки.Initializes a new instance of the ReaderWriterLockSlim class, specifying the lock recursion policy.

Свойства

CurrentReadCount CurrentReadCount CurrentReadCount CurrentReadCount

Получает общее количество уникальных потоков, вошедших в блокировку в режиме чтения.Gets the total number of unique threads that have entered the lock in read mode.

IsReadLockHeld IsReadLockHeld IsReadLockHeld IsReadLockHeld

Возвращает значение, указывающее, вошел ли текущий поток в блокировку в режиме чтения.Gets a value that indicates whether the current thread has entered the lock in read mode.

IsUpgradeableReadLockHeld IsUpgradeableReadLockHeld IsUpgradeableReadLockHeld IsUpgradeableReadLockHeld

Возвращает значение, указывающее, вошел ли текущий поток в блокировку в обновляемом режиме.Gets a value that indicates whether the current thread has entered the lock in upgradeable mode.

IsWriteLockHeld IsWriteLockHeld IsWriteLockHeld IsWriteLockHeld

Возвращает значение, указывающее, вошел ли текущий поток в блокировку в режиме записи.Gets a value that indicates whether the current thread has entered the lock in write mode.

RecursionPolicy RecursionPolicy RecursionPolicy RecursionPolicy

Возвращает значение, указывающее политику рекурсии для текущего объекта ReaderWriterLockSlim.Gets a value that indicates the recursion policy for the current ReaderWriterLockSlim object.

RecursiveReadCount RecursiveReadCount RecursiveReadCount RecursiveReadCount

Возвращает количество раз, которые текущий поток входил в блокировку в режиме чтения, как показатель рекурсии.Gets the number of times the current thread has entered the lock in read mode, as an indication of recursion.

RecursiveUpgradeCount RecursiveUpgradeCount RecursiveUpgradeCount RecursiveUpgradeCount

Возвращает количество раз, которые текущий поток входил в блокировку в обновляемом режиме, как показатель рекурсии.Gets the number of times the current thread has entered the lock in upgradeable mode, as an indication of recursion.

RecursiveWriteCount RecursiveWriteCount RecursiveWriteCount RecursiveWriteCount

Возвращает количество раз, которые текущий поток входил в блокировку в режиме записи, как показатель рекурсии.Gets the number of times the current thread has entered the lock in write mode, as an indication of recursion.

WaitingReadCount WaitingReadCount WaitingReadCount WaitingReadCount

Возвращает общее количество потоков, ожидающих вхождения в блокировку в режиме чтения.Gets the total number of threads that are waiting to enter the lock in read mode.

WaitingUpgradeCount WaitingUpgradeCount WaitingUpgradeCount WaitingUpgradeCount

Возвращает общее количество потоков, ожидающих входа в блокировку в обновляемом режиме.Gets the total number of threads that are waiting to enter the lock in upgradeable mode.

WaitingWriteCount WaitingWriteCount WaitingWriteCount WaitingWriteCount

Возвращает общее количество потоков, ожидающих входа в блокировку в режиме записи.Gets the total number of threads that are waiting to enter the lock in write mode.

Методы

Dispose() Dispose() Dispose() Dispose()

Освобождает все ресурсы, используемые текущим экземпляром класса ReaderWriterLockSlim.Releases all resources used by the current instance of the ReaderWriterLockSlim class.

EnterReadLock() EnterReadLock() EnterReadLock() EnterReadLock()

Пытается выполнить вход в блокировку в режиме чтения.Tries to enter the lock in read mode.

EnterUpgradeableReadLock() EnterUpgradeableReadLock() EnterUpgradeableReadLock() EnterUpgradeableReadLock()

Пытается выполнить вход в блокировку в обновляемом режиме.Tries to enter the lock in upgradeable mode.

EnterWriteLock() EnterWriteLock() EnterWriteLock() EnterWriteLock()

Пытается выполнить вход в блокировку в режиме записи.Tries to enter the lock in write mode.

Equals(Object) Equals(Object) Equals(Object) Equals(Object)

Определяет, равен ли заданный объект текущему объекту.Determines whether the specified object is equal to the current object.

(Inherited from Object)
ExitReadLock() ExitReadLock() ExitReadLock() ExitReadLock()

Уменьшает счетчик глубины рекурсии для режима чтения, и выходит из режима чтения, если значение счетчик принял значение 0 (нуль).Reduces the recursion count for read mode, and exits read mode if the resulting count is 0 (zero).

ExitUpgradeableReadLock() ExitUpgradeableReadLock() ExitUpgradeableReadLock() ExitUpgradeableReadLock()

Уменьшает счетчик глубины рекурсии для обновляемого режима, и выходит из обновляемого режима, если счетчик принял значение 0 (нуль).Reduces the recursion count for upgradeable mode, and exits upgradeable mode if the resulting count is 0 (zero).

ExitWriteLock() ExitWriteLock() ExitWriteLock() ExitWriteLock()

Уменьшает счетчик глубины рекурсии для режима записи, и выходит из режима записи, если счетчик принял значение 0 (нуль).Reduces the recursion count for write mode, and exits write mode if the resulting count is 0 (zero).

GetHashCode() GetHashCode() GetHashCode() GetHashCode()

Служит хэш-функцией по умолчанию.Serves as the default hash function.

(Inherited from Object)
GetType() GetType() GetType() GetType()

Возвращает объект Type для текущего экземпляра.Gets the Type of the current instance.

(Inherited from Object)
MemberwiseClone() MemberwiseClone() MemberwiseClone() MemberwiseClone()

Создает неполную копию текущего объекта Object.Creates a shallow copy of the current Object.

(Inherited from Object)
ToString() ToString() ToString() ToString()

Возвращает строку, представляющую текущий объект.Returns a string that represents the current object.

(Inherited from Object)
TryEnterReadLock(Int32) TryEnterReadLock(Int32) TryEnterReadLock(Int32) TryEnterReadLock(Int32)

Пытается войти в блокировку в режиме чтения с необязательным указанием времени ожидания целым числом.Tries to enter the lock in read mode, with an optional integer time-out.

TryEnterReadLock(TimeSpan) TryEnterReadLock(TimeSpan) TryEnterReadLock(TimeSpan) TryEnterReadLock(TimeSpan)

Пытается войти в блокировку в режиме чтения с необязательным указанием времени ожидания.Tries to enter the lock in read mode, with an optional time-out.

TryEnterUpgradeableReadLock(Int32) TryEnterUpgradeableReadLock(Int32) TryEnterUpgradeableReadLock(Int32) TryEnterUpgradeableReadLock(Int32)

Пытается войти в блокировку в обновляемом режиме с необязательным указанием времени ожидания.Tries to enter the lock in upgradeable mode, with an optional time-out.

TryEnterUpgradeableReadLock(TimeSpan) TryEnterUpgradeableReadLock(TimeSpan) TryEnterUpgradeableReadLock(TimeSpan) TryEnterUpgradeableReadLock(TimeSpan)

Пытается войти в блокировку в обновляемом режиме с необязательным указанием времени ожидания.Tries to enter the lock in upgradeable mode, with an optional time-out.

TryEnterWriteLock(Int32) TryEnterWriteLock(Int32) TryEnterWriteLock(Int32) TryEnterWriteLock(Int32)

Пытается войти в блокировку в режиме записи с необязательным указанием времени ожидания.Tries to enter the lock in write mode, with an optional time-out.

TryEnterWriteLock(TimeSpan) TryEnterWriteLock(TimeSpan) TryEnterWriteLock(TimeSpan) TryEnterWriteLock(TimeSpan)

Пытается войти в блокировку в режиме записи с необязательным указанием времени ожидания.Tries to enter the lock in write mode, with an optional time-out.

Применяется к

Потокобезопасность

Данный тип потокобезопасен.This type is thread safe.