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 parameterless constructor to create the lock, so recursion is not allowed. 當鎖定不允許遞迴時,程式設計會比較簡單且較不容易發生錯誤。ReaderWriterLockSlimProgramming 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 的效能明顯優於 ReaderWriterLockIn addition, the performance of ReaderWriterLockSlim is significantly better than ReaderWriterLock. 建議針對所有新的開發使用 ReaderWriterLockSlimReaderWriterLockSlim 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. 若要直接處置型別,請呼叫其 try/catch 區塊中的 Dispose 方法。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.

    注意

    執行緒可以使用EnterReadLockTryEnterReadLock方法, 或從可升級模式降級, 進入讀取模式的鎖定。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) 讀取 (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在可升級模式下開始, 則會進入讀取模式。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()

取得目前執行個體的 TypeGets the Type of the current instance.

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

建立目前 Object 的淺層複本 (Shallow Copy)。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.