List<int> list = new List<int>(); // 保護するリソース SpinLock spinLock = new SpinLock(); Action action = () => { for (int i = 0; i < 10000; i++) { bool lockTaken = false; try { spinLock.Enter(ref lockTaken); list.Add(i); } finally { if (lockTaken) spinLock.Exit(); } } }; Parallel.Invoke(action, action, action, action);例 - SpinLock 構造体 (System.Threading) | Microsoft Learn
SpinLockは、アプリケーションのパフォーマンスが向上する場合にのみ使用するようにします。
Remarks - SpinLock Struct (System.Threading) | Microsoft LearnSpinLock | Monitor |
---|---|
SpinLock spinLock = new SpinLock();
bool lockTaken = false;
try
{
spinLock.Enter(ref lockTaken);
// 共有リソースへのアクセス
}
finally
{
if (lockTaken) spinLock.Exit();
}
|
object sync = new object(); bool lockTaken = false; try { Monitor.Enter(sync, ref lockTaken); // 共有リソースへのアクセス } finally { if (lockTaken) Monitor.Exit(sync); } |
public SpinLock (bool enableThreadOwnerTracking);SpinLock(Boolean) Constructor (System.Threading) | Microsoft Learn
enableThreadOwnerTrackingをtrueとすると、デバッグのためにスレッドIDを使用するようになります。これを有効にするとスレッド追跡モード (Thread-Tracking Mode) となり、同一のスレッドでロックを再取得しようとすると例外が投げられるようになります。スレッド追跡モード - 方法: SpinLock のスレッド追跡モードを有効にする | Microsoft Learn
引数のないコンストラクタでは、このenableThreadOwnerTrackingは既定でtrueとなります。またこの値は、IsThreadOwnerTrackingEnabledプロパティで確認できます。
SpinLock spinLock1 = new SpinLock(false);
bool lockTaken = false;
spinLock1.Enter(ref lockTaken);
lockTaken = false;
spinLock1.Enter(ref lockTaken); // デッドロックする
SpinLock spinLock2 = new SpinLock();
bool lockTaken = false;
spinLock2.Enter(ref lockTaken);
lockTaken = false;
spinLock2.Enter(ref lockTaken); // LockRecursionException「呼び出しスレッドは既にロックを保持しています。」
信頼できる方法でロックを取得できます。
public void TryEnter ( int millisecondsTimeout, // 待機時間 ref bool lockTaken // ロックを得られたらtrue );TryEnter(Int32, Boolean) - SpinLock.TryEnter Method (System.Threading) | Microsoft Learn
ロックを入手できるか、millisecondsTimeoutが終了するまでブロックされます。
ロックを解放できます。
public void Exit (
bool useMemoryBarrier // trueならば、終了を他のスレッドにただちに公開するためのメモリフェンス (memory fence / memory barrier) を発行する
);
Exit(Boolean) - SpinLock.Exit Method (System.Threading) | Microsoft Learn
useMemoryBarrierをtrueとすると、パフォーマンスを費やしてロックの公平性を向上させます。既定のExit()のオーバーロードでは、useMemoryBarrierにtrueを指定したように動作します。