Win32のクリティカル セクション同等の機能が提供されます。このクラスの機能は、lockステートメントによって簡潔に実装できます。
Monitorは静的クラスのため、コンストラクタはありません。
指定のオブジェクトの排他ロックを得られます。
public static void Enter(
object obj // モニター ロックを取得する対象となるオブジェクト
)
Enter(Object) - Monitor.Enter Method (System.Threading) | Microsoft Learn
他のスレッドがobjを対象にロックを取得していると、そのスレッドがそれを解放するまで現在のスレッドはブロックされます。
object lockObj = new Object();
Monitor.Enter(lockObj);
try
{
// クリティカル セクション (critical section)
}
finally
{
Monitor.Exit(lockObj);
}
ロックを得られたことを知りたいならば、lockTakenを渡せるオーバーロードを用います。一方でロックを取得できるか事前に知りたいならば、TryEnter()を用います。
public static void Enter (object obj, ref bool lockTaken);
lockTakenはfalseに設定してから渡します。そしてロックを得られたならばtrueに設定されます。ただし例外が投げられなければ、つねにtrueです。
指定のオブジェクトの排他ロックの取得を試みられます。
public static bool TryEnter (object obj);TryEnter(Object) - Monitor.TryEnter Method (System.Threading) | Microsoft Learn
このメソッドは即座に取得できなければfalseを返すため、取得できるまで待たせるならばタイムアウトの時間を指定できる形式を用います。
public static bool TryEnter (
object obj,
int millisecondsTimeout // ロックを待つ時間
);
TryEnter(Object, Int32) - Monitor.TryEnter Method (System.Threading) | Microsoft Learn
millisecondsTimeoutをTimeout.Infinite (-1) とするとタイムアウトしません。-1ではない負数を指定すると、ArgumentOutOfRangeExceptionが投げられます。
millisecondsTimeoutは、ロックを得られるまで待つ時間の最大値です。
object lockObj = new Object();
int timeout = 500;
if (Monitor.TryEnter(lockObj, timeout))
{
try
{
// クリティカル セクション (critical section)
}
finally
{
Monitor.Exit(lockObj);
}
}
else
{
// ロックを得られなかった
}
取得したロックは、Exit()で解放します。
ロックを解放できます。
public static void Exit (object obj);Monitor.Exit(Object) Method (System.Threading) | Microsoft Learn
ロックは、それを取得したスレッドで解放しなければなりません。これはlockと同様で、スレッドが異なるならばSemaphoreSlimを用います。c# - SynchronizationLockException on Monitor.Exit when using await - Stack Overflow
object lockObj = new Object();
Monitor.Enter(lockObj);
try
{
await Task.Delay(10).ConfigureAwait(false);
}
finally
{
// ここはEnter()を呼び出したときとは異なるスレッド
Monitor.Exit(lockObj); // SynchronizationLockException「オブジェクト同期メソッドは、コードの非同期ブロックから呼び出されました。」
}
オブジェクトのロックを解放し、そのロックを再取得するまで現在のスレッドをロックできます。
ロックされたオブジェクトの状態の変化を、待機キュー (waiting queue) 内のスレッドに通知できます。