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. のインスタンスはReaderWriterLockSlimDictionary<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. ロックで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. 3つのタスクが作成されます。It creates three tasks. 最初のSynchronizedCache例では、配列に格納されている野菜の名前をインスタンスに書き込みます。The first writes the names of vegetables stored in an array to a SynchronizedCache instance. 2番目と3番目のタスクは、野菜の名前を表示します。最初の部分は昇順 (小さいインデックスから大きいインデックスの順)、2番目のタスクは降順です。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メソッドを呼び出して文字列 "green 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のスレッドによって読み取られ、一度に1つのスレッドによって書き込まれるリソースを保護するために使用します。Use ReaderWriterLockSlim to protect a resource that is read by multiple threads and written to by one thread at a time. ReaderWriterLockSlim複数のスレッドを読み取りモードにし、1つのスレッドがロックの排他所有権を持つ書き込みモードにできるようにします。また、読み取りアクセス権を持つ1つのスレッドを、アップグレード可能な読み取りモードにすることができます。これにより、スレッドは、解放せずに書き込みモードにアップグレードできます。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.

注意

ReaderWriterLockSlimReaderWriterLock と似ていますが、再帰の規則や、ロック状態のアップグレードおよびダウングレードの規則が簡素化されています。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を使用ReaderWriterLockSlimする既存のプロジェクトからの移行を簡単にするために、フラグを使用して、再帰を許可するのインスタンスを作成できます。LockRecursionPolicy.SupportsRecursionTo 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.

スレッドは、読み取りモード、書き込みモード、およびアップグレード可能な読み取りモードの3つのモードでロックに入ることができます。A thread can enter the lock in three modes: read mode, write mode, and upgradeable read mode. (このトピックの残りの部分では、"アップグレード可能な読み取りモード" を "アップグレード可能モード" と呼びます。 x "enter モード" という語句は、長い語句 "mode in x mode を入力する" に優先して使用されます)。(In the rest of this topic, "upgradeable read mode" is referred to as "upgradeable mode", and the phrase "enter x mode" is used in preference to the longer phrase "enter the lock in x mode".)

再帰ポリシーに関係なく、一度に1つのスレッドだけが書き込みモードになることがあります。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. アップグレード可能モードでは、いつでも1つのスレッドを使用できます。Only one thread can be in upgradeable mode at any time. 任意の数のスレッドを読み取りモードにすることができます。また、他のスレッドが読み取りモードの間は、アップグレード可能モードで1つのスレッドを使用できます。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:

  • 書き込みモードに入るのを待機しているスレッドがある場合、または書き込みモードで1つのスレッドがある場合は、読み取りモードを開始しようとするスレッドがブロックされます。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.

  • アップグレード可能モードでスレッドが既に存在する場合、書き込みモードに入るのを待機しているスレッドがある場合、または書き込みモードのスレッドが1つの場合は、アップグレード可能モードに入ろうとするスレッドがブロックされます。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.

  • 3つのモードのいずれかにスレッドがある場合は、書き込みモードに入ろうとするスレッドがブロックされます。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. アップグレード可能モードのスレッドは一度に1つしか存在できないため、再帰が許可されていない場合 (既定のポリシー)、書き込みモードへのアップグレードはデッドロックを行うことができません。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. たとえば、読み取りモードの2つのスレッドが書き込みモードに入る場合、デッドロックが発生します。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.

重要

複数のスレッドが書き込みモードまたはアップグレード可能モードに入ることを許可する場合は、1つのスレッドがアップグレード可能モードを独占できないようにする必要があります。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.

再帰を許可するの場合、スレッドが入力できるモードについて次のようになります。 ReaderWriterLockSlimFor 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.

  • アップグレード可能モードのスレッドは、書き込みモードまたは読み取りモードにすることができ、3つのモードのいずれかを再帰的に入力できます。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.

  • 書き込みモードのスレッドは、読み取りモードまたはアップグレード可能モードにすることができ、3つのモードのいずれかを再帰的に入力できます。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 、"入力なし"、"読み取り"、"アップグレード"、および "書き込み" の4つの状態のいずれかになります。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).

  • 込んこの状態では、1つまたは複数のスレッドが、保護されたリソースへの読み取りアクセスのロックに入っています。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.

  • 増設この状態では、1つのスレッドが読み取りアクセスのロックに入り、書き込みアクセスにアップグレードするオプション (アップグレード可能モード) と、0個以上のスレッドが読み取りアクセスのロックに入りました。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. アップグレードするオプションを使用して、一度に1つ以上のスレッドがロックに入ることはできません。アップグレード可能モードに入ろうとした追加のスレッドはブロックされます。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.

  • 企画この状態では、1つのスレッドが、保護されたリソースへの書き込みアクセスのロックに入っています。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.

1tアップグレード可能モードで起動すると、読み取りモードになります。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 アップグレード可能モードでが起動すると、読み取りモードのスレッドがある場合はブロックされます。t2 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:

  • まず、書き込みモードを待機していて、既にアップグレード可能モードになっているスレッドがあります (このようなスレッドは1つしか存在できません)。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.

最初の2つのケースでは、その後のロックの状態は常に書き込み (W) になります。3番目のケースでは、終了したスレッドが状態の変更をトリガーしたときのロックの状態に関係なく、アップグレード (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. 最後のケースでは、状態の変更後にアップグレード可能モードでスレッドが存在する場合、ロックの状態は Upgrade (U) になり、それ以外の場合は前の状態に関係なく読み取り (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.