ReaderWriterLockSlim クラス

定義

リソースへのアクセス管理に使用するロックを表し、複数のスレッドによる読み取りや排他アクセスでの書き込みを実現します。

public ref class ReaderWriterLockSlim : IDisposable
public class ReaderWriterLockSlim : IDisposable
type ReaderWriterLockSlim = class
    interface IDisposable
Public Class ReaderWriterLockSlim
Implements IDisposable
継承
ReaderWriterLockSlim
実装

次の例は、整数キーを持つ文字列を保持する単純な同期キャッシュを示しています。 インスタンス ReaderWriterLockSlim は、内部キャッシュとして機能するインスタンスへの Dictionary<TKey,TValue> アクセスを同期するために使用されます。

この例には、キャッシュに追加し、キャッシュから削除し、キャッシュから読み取る簡単なメソッドが含まれています。 タイムアウトを示すために、この例には、指定されたタイムアウト内でキャッシュに追加できる場合にのみ追加するメソッドが含まれています。

アップグレード可能モードを示すために、この例には、キーに関連付けられている値を取得し、それを新しい値と比較するメソッドが含まれています。 値が変更されていない場合、メソッドは変更がないことを示す状態を返します。 キーの値が見つからない場合は、キーと値のペアが挿入されます。 値が変更された場合は更新されます。 アップグレード可能モードを使用すると、スレッドは読み取りアクセスから必要に応じて書き込みアクセスにアップグレードでき、デッドロックのリスクはありません。

この例には、アップグレード可能モードを示すメソッドの戻り値を指定する入れ子になった列挙体が含まれています。

この例では、パラメーターなしのコンストラクターを使用してロックを作成するため、再帰は許可されません。 ロックで ReaderWriterLockSlim 再帰が許可されない場合は、プログラミングが簡単になり、エラーが発生しにくくなります。

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 使用して野菜名の辞書を格納します。 3 つのタスクを作成します。 1 つ目は、配列に格納されている野菜の名前をインスタンスに SynchronizedCache 書き込みます。 2 番目と 3 番目のタスクでは、野菜の名前が表示されます。1 つ目は昇順 (低いインデックスから高いインデックスまで)、2 番目は降順で表示されます。 最後のタスクは文字列 "きゅうり" を検索し、見つかると、文字列 "green Bean" の代わりにメソッドを呼び出します EnterUpgradeableReadLock

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 = ctr == 1;
         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

注釈

複数のスレッドによって読み取られ、一度に 1 つのスレッドによって書き込まれるリソースを保護するために使用 ReaderWriterLockSlim します。 ReaderWriterLockSlim では、複数のスレッドが読み取りモードになり、1 つのスレッドがロックの排他的所有権を持つ書き込みモードになり、読み取りアクセス権を持つ 1 つのスレッドをアップグレード可能な読み取りモードにすることができます。これにより、スレッドはリソースへの読み取りアクセス権を放棄することなく、書き込みモードにアップグレードできます。

注意

  • ReaderWriterLockSlimReaderWriterLock と似ていますが、再帰の規則や、ロック状態のアップグレードおよびダウングレードの規則が簡素化されています。 ReaderWriterLockSlim は、デッドロックの可能性を大幅に回避します。 さらに、ReaderWriterLockSlim のパフォーマンスは ReaderWriterLock と比較して格段に優れています。 すべての新規開発で、ReaderWriterLockSlim を使用することをお勧めします。
  • ReaderWriterLockSlim はスレッド中止セーフではありません。 .NET Frameworkなど、アクセスするスレッドを中止できる環境では使用しないでください。 .NET Core または .NET 5 以降を使用している場合は、問題ありません。 Abort は .NET Core ではサポートされておらず、.NET 5 以降のバージョンでは 廃止 されています。

既定では、フラグを ReaderWriterLockSlim 使用して新しいインスタンスが LockRecursionPolicy.NoRecursion 作成され、再帰は許可されません。 再帰では不要な複雑さが発生し、コードのデッドロックが発生しやすくなるため、この既定のポリシーはすべての新しい開発に推奨されます。 使用またはReaderWriterLock使用Monitorする既存のプロジェクトからの移行を簡略化するために、フラグをLockRecursionPolicy.SupportsRecursion使用して、再帰を許可するインスタンスReaderWriterLockSlimを作成できます。

スレッドは、読み取りモード、書き込みモード、アップグレード可能読み取りモードの 3 つのモードでロックを開始できます。 (このトピックの残りの部分では、"アップグレード可能な読み取りモード" は "アップグレード可能モード" と呼ばれ、"モードに入る" という長い語句を優先して "モードxに入xる" という語句が使用されます)。

再帰ポリシーに関係なく、書き込みモードにできるスレッドは 1 つだけです。 スレッドが書き込みモードの場合、他のスレッドはどのモードでもロックを開始できません。 アップグレード可能モードにできるスレッドは、いつでも 1 つだけです。 任意の数のスレッドを読み取りモードにすることができ、1 つのスレッドをアップグレード可能モードにして、他のスレッドを読み取りモードにすることができます。

重要

この型は IDisposable インターフェイスを実装します。 型の使用が完了したら、直接的または間接的に型を破棄する必要があります。 直接的に型を破棄するには、try/catch ブロック内で Dispose メソッドを呼び出します。 間接的に型を破棄するには、using (C# の場合) または Using (Visual Basic 言語) などの言語構成要素を使用します。 詳細については、IDisposable インターフェイスに関するトピック内の「IDisposable を実装するオブジェクトの使用」セクションを参照してください。

ReaderWriterLockSlim にはマネージド スレッド アフィニティがあります。つまり、ロック モードを開始および終了するには、各 Thread オブジェクトが独自のメソッド呼び出しを行う必要があります。 スレッドが別のスレッドのモードを変更することはできません。

a が ReaderWriterLockSlim 再帰を許可しない場合、ロックに入ろうとするスレッドは、いくつかの理由でブロックする可能性があります。

  • 書き込みモードの開始を待機しているスレッドがある場合、または書き込みモードで単一のスレッドがある場合に、読み取りモード ブロックに入ろうとするスレッド。

    注意

    ライターがキューに登録されたときに新しいリーダーをブロックすることは、ライターを優先するロックの公平性ポリシーです。 現在の公平性ポリシーは、最も一般的なシナリオでスループットを促進するために、読者とライターに公平性のバランスを取ります。 .NET Frameworkの将来のバージョンでは、新しい公平性ポリシーが導入される可能性があります。

  • 既にアップグレード可能モードのスレッドがある場合、書き込みモードの開始を待機しているスレッドがある場合、または書き込みモードでスレッドが 1 つある場合に、アップグレード可能モードに入ろうとするスレッドがブロックされます。

  • 3 つのモードのいずれかにスレッドがある場合に、書き込みモードブロックに入ろうとするスレッド。

ロックのアップグレードとダウングレード

アップグレード可能モードは、通常、スレッドが保護されたリソースから読み取るが、何らかの条件が満たされた場合に書き込みが必要になる場合を対象としています。 アップグレード可能モードに入ったReaderWriterLockSlimスレッドは、保護されたリソースへの読み取りアクセス権を持ち、またはTryEnterWriteLockメソッドを呼び出すことによって書き込みモードにEnterWriteLockアップグレードできます。 アップグレード可能モードでは一度に 1 つのスレッドしか存在できないため、再帰が許可されていない場合、書き込みモードへのアップグレードはデッドロックできません。これは既定のポリシーです。

重要

再帰ポリシーに関係なく、最初に読み取りモードに入ったスレッドは、アップグレード可能モードまたは書き込みモードにアップグレードできません。これは、そのパターンによってデッドロックが発生する可能性が高いためです。 たとえば、読み取りモードの 2 つのスレッドが両方とも書き込みモードに入ろうとすると、デッドロックが発生します。 アップグレード可能モードは、このようなデッドロックを回避するように設計されています。

読み取りモードの他のスレッドがある場合は、ブロックをアップグレードしているスレッド。 スレッドがブロックされている間、読み取りモードに入ろうとする他のスレッドはブロックされます。 すべてのスレッドが読み取りモードから終了すると、ブロックされたアップグレード可能なスレッドは書き込みモードになります。 書き込みモードへの入りを待機している他のスレッドがある場合は、アップグレード可能モードの単一スレッドがリソースへの排他的アクセスを取得できないため、ブロックされたままです。

アップグレード可能モードのスレッドが書き込みモードを終了すると、読み取りモードに入るのを待機している他のスレッドは、書き込みモードに入るのを待機しているスレッドがない限り、これを行うことができます。 アップグレード可能モードのスレッドは、保護されたリソースに書き込む唯一のスレッドである限り、無期限にアップグレードおよびダウングレードできます。

重要

複数のスレッドが書き込みモードまたはアップグレード可能モードに入ることを許可する場合は、1 つのスレッドがアップグレード可能モードを独占できないようにする必要があります。 それ以外の場合、書き込みモードに直接入ろうとしたスレッドは無期限にブロックされ、ブロックされている間は、他のスレッドは読み取りモードに入ることができません。

アップグレード可能モードのスレッドは、最初にメソッドを呼び出してからメソッドを EnterReadLock 呼び出すことによって、読み取りモードに ExitUpgradeableReadLock ダウングレードできます。 このダウングレード パターンは、すべてのロック再帰ポリシーでも NoRecursion許可されます。

読み取りモードにダウングレードした後、スレッドは読み取りモードから終了するまでアップグレード可能モードに再入できません。

ロックを再帰的に入力する

ロック ポリシーを ReaderWriterLockSlim 指定するコンストラクターを使用して、再帰的なロック エントリを ReaderWriterLockSlim(LockRecursionPolicy) サポートするオブジェクトを作成し、指定できます LockRecursionPolicy.SupportsRecursion

注意

再帰の使用は、不要な複雑さが発生し、コードがデッドロックを起こしやすいため、新しい開発にはお勧めしません。

再帰を許可する a ReaderWriterLockSlim の場合、スレッドが入力できるモードについて次のように言うことができます。

  • 読み取りモードのスレッドは再帰的に読み取りモードに入ることができますが、書き込みモードまたはアップグレード可能モードに入ることはできません。 これを行おうとすると、a LockRecursionException がスローされます。 読み取りモードに入ってから書き込みモードまたはアップグレード可能モードに入ると、デッドロックの可能性が高いパターンであるため、許可されません。 前述のように、ロックをアップグレードする必要がある場合にアップグレード可能モードが提供されます。

  • アップグレード可能モードのスレッドは、書き込みモードまたは読み取りモードに入ることができ、3 つのモードのいずれかを再帰的に入力できます。 ただし、読み取りモードで他のスレッドがある場合は、書き込みモードブロックに入ろうとします。

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

  • ロックに入っていないスレッドは、任意のモードに入ることができます。 この試行は、非再帰ロックを入力する場合と同じ理由でブロックできます。

スレッドは、各モードをそのモードに入ったのとまったく同じ回数終了する限り、任意の順序で入力したモードを終了できます。 スレッドがモードを何度も終了しようとした場合、またはスレッドが入っていないモードを終了しようとすると、a SynchronizationLockException がスローされます。

ロックの状態

ロックの状態の観点から考えると便利な場合があります。 A ReaderWriterLockSlim は、入力されていない、読み取り、アップグレード、書き込みの 4 つの状態のいずれかになります。

  • 未入力: この状態では、スレッドがロックに入っていません (または、すべてのスレッドがロックを終了しました)。

  • 読み取り: この状態では、1 つ以上のスレッドが、保護されたリソースへの読み取りアクセスのロックに入っています。

    注意

    スレッドは、読み取りモードでロックを開始するには、メソッドをEnterReadLockTryEnterReadLock使用するか、アップグレード可能モードからダウングレードします。

  • アップグレード: この状態では、1 つのスレッドが読み取りアクセスのロックに入り、書き込みアクセスをアップグレードするオプション (つまり、アップグレード可能モード) が設定され、0 個以上のスレッドが読み取りアクセスのロックに入っています。 アップグレードするオプションを使用してロックを入力できるスレッドは、一度に 1 つ以上ありません。アップグレード可能モードに入ろうとする追加のスレッドはブロックされます。

  • 書き込み: この状態では、1 つのスレッドが保護されたリソースへの書き込みアクセスのロックに入っています。 そのスレッドはロックを排他的に所有しています。 何らかの理由でロックに入ろうとする他のスレッドはブロックされます。

次の表では、スレッド t が左端の列で説明されているアクションを実行するときに、再帰を許可しないロックのロック状態間の遷移について説明します。 アクションを実行する時点で、 t モードはありません。 (アップグレード可能モードの特殊なケース t については、表の脚注を参照してください)。上部の行は、ロックの開始状態を示します。 セルはスレッドの動作を説明し、ロック状態の変更をかっこで囲んで表示します。

未入力 (N) 読み取り (R) アップグレード (U) 書き込み (W)
t 読み取りモードに入る t enters (R)。 t スレッドが書き込みモードを待機している場合はブロックされます。それ以外の場合は、 t 次のように入力します。 t スレッドが書き込みモードを待機している場合はブロックされます。それ以外の場合は、 t 次のように入力します。1 t ブロック。
t アップグレード可能モードに入る t enters (U)。 t スレッドが書き込みモードまたはアップグレード モードを待機している場合はブロックされます。それ以外の場合は、 t (U) と入力します。 t ブロック。 t ブロック。
t 書き込みモードに入る t (W) と入力します。 t ブロック。 t ブロック。2 t ブロック。

1 t アップグレード可能モードで起動すると、読み取りモードになります。 このアクションはブロックしません。 ロック状態は変更されません。 (スレッドは、アップグレード可能モードを終了することで、読み取りモードへのダウングレードを完了できます)。

2 アップグレード可能モードで開始すると t 、読み取りモードのスレッドがあるかどうかをブロックします。 それ以外の場合は、書き込みモードにアップグレードされます。 ロック状態が書き込み (W) に変わります。 読み取りモードのスレッドがあるためにブロックする場合 t は、書き込みモードに入るスレッドがある場合でも、最後のスレッドが読み取りモードを終了するとすぐに書き込みモードになります。

スレッドがロックを終了したために状態の変更が発生した場合、次のように、次のスレッドが起動されます。

  • 最初に、書き込みモードを待機していて、既にアップグレード可能モードになっているスレッド (そのようなスレッドは最大で 1 つ存在する可能性があります)。

  • 失敗した場合、書き込みモードを待機しているスレッド。

  • 失敗した場合、アップグレード可能モードを待機しているスレッド。

  • 失敗すると、読み取りモードを待機しているすべてのスレッド。

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

コンストラクター

ReaderWriterLockSlim()

ReaderWriterLockSlim クラスの新しいインスタンスを既定のプロパティ値で初期化します。

ReaderWriterLockSlim(LockRecursionPolicy)

ロック再帰ポリシーを指定して、ReaderWriterLockSlim クラスの新しいインスタンスを初期化します。

プロパティ

CurrentReadCount

読み取りモードでロックに入った一意のスレッドの総数を取得します。

IsReadLockHeld

現在のスレッドが読み取りモードでロックに入ったかどうかを示す値を取得します。

IsUpgradeableReadLockHeld

現在のスレッドがアップグレード可能モードでロックに入ったかどうかを示す値を取得します。

IsWriteLockHeld

現在のスレッドが書き込みモードでロックに入ったかどうかを示す値を取得します。

RecursionPolicy

現在の ReaderWriterLockSlim オブジェクトの再帰ポリシーを示す値を取得します。

RecursiveReadCount

現在のスレッドが読み取りモードでロックに入った回数を、再帰を示す値として取得します。

RecursiveUpgradeCount

現在のスレッドがアップグレード可能モードでロックに入った回数を、再帰を示す値として取得します。

RecursiveWriteCount

現在のスレッドが書き込みモードでロックに入った回数を、再帰を示す値として取得します。

WaitingReadCount

読み取りモードでロックに入るのを待機しているスレッドの総数を取得します。

WaitingUpgradeCount

アップグレード可能モードでロックに入るのを待機しているスレッドの総数を取得します。

WaitingWriteCount

書き込みモードでロックに入るのを待機しているスレッドの総数を取得します。

メソッド

Dispose()

ReaderWriterLockSlim クラスの現在のインスタンスによって使用されているすべてのリソースを解放します。

EnterReadLock()

読み取りモードでロックに入ることを試みます。

EnterUpgradeableReadLock()

アップグレード可能モードでロックに入ることを試みます。

EnterWriteLock()

書き込みモードでロックに入ることを試みます。

Equals(Object)

指定されたオブジェクトが現在のオブジェクトと等しいかどうかを判断します。

(継承元 Object)
ExitReadLock()

読み取りモードの再帰カウントを減らし、結果のカウントが 0 (ゼロ) の場合には読み取りモードを終了します。

ExitUpgradeableReadLock()

アップグレード可能モードの再帰カウントを減らし、結果のカウントが 0 (ゼロ) の場合にはアップグレード可能モードを終了します。

ExitWriteLock()

書き込みモードの再帰カウントを減らし、結果のカウントが 0 (ゼロ) の場合には書き込みモードを終了します。

GetHashCode()

既定のハッシュ関数として機能します。

(継承元 Object)
GetType()

現在のインスタンスの Type を取得します。

(継承元 Object)
MemberwiseClone()

現在の Object の簡易コピーを作成します。

(継承元 Object)
ToString()

現在のオブジェクトを表す文字列を返します。

(継承元 Object)
TryEnterReadLock(Int32)

オプションのタイムアウトを表す整数を指定して、読み取りモードでロックに入ることを試みます。

TryEnterReadLock(TimeSpan)

オプションのタイムアウトを指定して、読み取りモードでロックに入ることを試みます。

TryEnterUpgradeableReadLock(Int32)

オプションのタイムアウトを指定して、アップグレード可能モードでロックに入ることを試みます。

TryEnterUpgradeableReadLock(TimeSpan)

オプションのタイムアウトを指定して、アップグレード可能モードでロックに入ることを試みます。

TryEnterWriteLock(Int32)

オプションのタイムアウトを指定して、書き込みモードでロックに入ることを試みます。

TryEnterWriteLock(TimeSpan)

オプションのタイムアウトを指定して、書き込みモードでロックに入ることを試みます。

適用対象

スレッド セーフ

この型はスレッド セーフです。