ReaderWriterLockクラス

これと似たクラスにReaderWriterLockSlimがあり、こちらは

  • 再帰の規則が簡素化
  • ロック状態の昇格 (upgrading) や 降格 (downgrading) の規則が簡素化
  • デッドロックの可能性が減少
  • パフォーマンスが著しく向上

しているため、特段の理由がなければReaderWriterLockSlimクラスを使用します。Remarks - ReaderWriterLock Class (System.Threading) | Microsoft Learn

ReaderWriterLockは共有リソースに対する読み取りが多く、書き込みの頻度が少ない場合に効果を発揮します。そうではないならば、より単純なlockステートメントの使用を検討します。

メソッド

AcquireReaderLock()

リーダーロックを取得できます。

public void AcquireReaderLock (int millisecondsTimeout);
AcquireReaderLock(Int32) - ReaderWriterLock.AcquireReaderLock メソッド (System.Threading) | Microsoft Learn

別のスレッドにライターロックがあるか、ライターロックの取得を待っている間は、このメソッドは現在のスレッドをブロックします。それ以外ならば、スレッドはブロックされません

現在のスレッドにライターロックがある場合はAcquireWriterLock()の呼び出しと同じとなり、そのロックの解放にはReleaseWriterLock()が必要となります。

AcquireReaderLock()を複数回呼ぶことでリーダーロックをくり返し (再帰的に) 要求できますが、それと同数ReleaseReaderLock()を呼ばなければなりません。またはReleaseLock()で、ロック数とは無関係にロックを解放することもできます。

millisecondsTimeoutを0以下とすると、特別な意味となります。Remarks - ReaderWriterLock Class (System.Threading) | Microsoft Learn

  • -1 … ロックを得るまで待つ。Timeout.Infiniteとも指定できる
  • 0 または -1ではない負数 … ロックを得るまで待たない。即座にロックを得られなければ、メソッドは戻る
  • 0より大きい … 指定の時間まで待つ
ReaderWriterLock rwLock = new ReaderWriterLock();
try
{
    int timeout = 10;
    rwLock.AcquireReaderLock(timeout);

    try
    {
        // 共有リソースからの読み取り
    }
    finally
    {
        rwLock.ReleaseReaderLock();
    }
}
catch (ApplicationException e)
{
    // ロックの取得前にタイムアウトした
}

ロックの取得と解放を管理するクラスを用意すると、この処理をより簡潔に記述できます。c# - 'using' statement vs 'try finally' - Stack Overflow

AcquireWriterLock()

ライターロックを取得できます。

public void AcquireWriterLock (int millisecondsTimeout);
AcquireWriterLock(Int32) - ReaderWriterLock.AcquireWriterLock メソッド (System.Threading) | Microsoft Learn

他のスレッドにリーダーロックやライターロックがあるとき、このメソッドは現在のスレッドをブロックします。

現在のスレッドにリーダーロックがあるときにライターロックを取得するには、先にリーダーロックを解放するか、UpgradeToWriterLock()を呼びます。そのときAcquireWriterLock()を呼ぶと自身のリーダーロックをブロックするため、無限のタイムアウトを指定しているとデッドロックします。

ReaderWriterLock rwLock = new ReaderWriterLock();
try
{
    int timeout = 10;
    rwLock.AcquireWriterLock(timeout);

    try
    {
        // 共有リソースへの書き込み
    }
    finally
    {
        rwLock.ReleaseWriterLock();
    }
}
catch (ApplicationException e)
{
    // ロックの取得前にタイムアウトした
}

ReleaseLock()

ロックを取得した回数とは無関係に、ロックを解放できます。

public System.Threading.LockCookie ReleaseLock ();
ReaderWriterLock.ReleaseLock メソッド (System.Threading) | Microsoft Learn

RestoreLock()

スレッドのロックの状態を、ReleaseLock()を呼び出す前に戻せます。

public void RestoreLock (ref System.Threading.LockCookie lockCookie);
ReaderWriterLock.RestoreLock(LockCookie) メソッド (System.Threading) | Microsoft Learn
Microsoft Learnから検索