高性能ではないロックの場合...堅牢なスレッドセーフコードだけ...lock (obj) { code; }
構造の単純さが必要ですが、その前後にログを記録したいです(フィールドでデッドロックを取得することで簡単に確認できるように)ユーザーからのログ)、ReaderWriterLocks をサポートしたい。(はい、Monitor や SpinLock などの方が高速であることは認識していますが、これは高パフォーマンスでスレッド数が多いわけではありません... ここでは速度は問題ではありません。)
を介してこれを行うという提案を見たことusing (new ReadLock(myLock)) { code; }
がありますが、そこで新しく作成されたクラスのコーディングはしばしば疑わしいものでした。
すっごく、これが私が思いついたものです。皆さんへの私の質問: (1) コメントで示したように使用した場合、次のコードに問題はありますか? (2) このコードを改善して、より信頼性を高め、よりシンプルに、またはより効率的にする方法について何か提案はありますか?
TccLog は、log4net のラッパーにすぎないことに注意してください...しかし、選択したログ ライブラリが何であれ、それは可能性があります。
// Locks.cs == structs intended to be used with using statements for reliable, easy-to-code, logged locks
using System;
using System.Threading;
namespace Tcc.Common
{
/// <summary>
/// A ReadLock allows any number of readers but prevents any writers until the ReadLock is disposed.
/// ReadLocks do NOT log as they can't cause deadlocks without some other thread having a WriteLock.
/// Use a ReadLock with the following syntax:
///
/// using (new ReadLock(someReaderWriterLock, timeoutInMS))
/// { code; }
///
/// which is equivalent to:
///
/// someReaderWriterLock.AcquireReaderLock(timeoutInMS);
/// try
/// { code; }
/// finally
/// { someReaderWriterLock.ReleaseReaderLock(); }
/// </summary>
public struct ReadLock : IDisposable
{
ReaderWriterLock TheLock;
public ReadLock(ReaderWriterLock theLock)
{
TheLock = theLock;
TheLock.AcquireReaderLock(100000);
}
public ReadLock(ReaderWriterLock theLock, int timeoutMS)
{
TheLock = theLock;
TheLock.AcquireReaderLock(timeoutMS);
}
public void Dispose()
{
TheLock.ReleaseReaderLock();
}
}
/// <summary>
/// A WriteLock allows only that one writer and no readers.
/// WriteLocks will log when they start waiting for the lock and again when they release the lock.
/// You may want to log.TraceLock("LOCKED") in the first line of your code that you have acquired the lock.
/// Use a WriteLock with the following syntax:
///
/// using (new WriteLock(someReaderWriterLock, timeoutInMS))
/// { code; }
///
/// which is equivalent to:
///
/// LOG.TraceLock("LOCKING");
/// someReaderWriterLock.AcquireWriterLock(timeoutInMS);
/// try
/// { code; }
/// finally
/// { someReaderWriterLock.ReleaseWriterLock(); LOG.TraceLock("UNLOCKED"); }
/// </summary>
public struct WriteLock : IDisposable
{
private static TccLog LOG = new TccLog(2);
ReaderWriterLock TheLock;
public WriteLock(ReaderWriterLock theLock)
{
TheLock = theLock;
LOG.TraceLock("LOCKING");
TheLock.AcquireWriterLock(100000);
}
public WriteLock(ReaderWriterLock theLock, int timeoutMS)
{
TheLock = theLock;
LOG.TraceLock("LOCKING");
TheLock.AcquireWriterLock(timeoutMS);
}
public void Dispose()
{
TheLock.ReleaseWriterLock();
LOG.TraceLock("UNLOCKED");
}
}
/// <summary>
/// A FullLock is like the built-in 'lock' (Monitor on any heap object), except it implements logging.
/// FullLocks will log when they start waiting for the lock and again when they release the lock.
/// You may want to log.TraceLock("LOCKED") in the first line of your code that you have acquired the lock.
/// Use a FullLock with the following syntax:
///
/// using (new FullLock(someHeapObject))
/// { code; }
///
/// which is equivalent to:
///
/// LOG.TraceLock("LOCKING");
/// lock (someHeapObject)
/// { code; }
/// LOG.TraceLock("UNLOCKED");
/// </summary>
public struct FullLock : IDisposable
{
private static TccLog LOG = new TccLog(2);
object TheLock;
public FullLock(object theLock)
{
TheLock = theLock;
LOG.TraceLock("LOCKING");
Monitor.Enter(TheLock);
}
public void Dispose()
{
Monitor.Exit(TheLock);
LOG.TraceLock("UNLOCKED");
}
}
/// <summary>
/// A NamedLock is like the built-in 'lock' (Monitor on any heap object), except it implements logging.
/// NamedLocks will log when they start waiting for the lock and again when they release the lock.
/// You may want to log.TraceLock("LOCKED") in the first line of your code that you have acquired the lock.
/// Use a NamedLock with the following syntax:
///
/// using (new NamedLock(someHeapObject, "name"))
/// { code; }
///
/// which is equivalent to:
///
/// LOG.TraceLock("LOCKING name");
/// lock (someHeapObject)
/// { code; }
/// LOG.TraceLock("UNLOCKED name");
/// </summary>
public struct NamedLock : IDisposable
{
private static TccLog LOG = new TccLog(2);
object TheLock;
string Name;
public NamedLock(object theLock, string name)
{
Name = name;
TheLock = theLock;
LOG.TraceLock("LOCKING " + name);
Monitor.Enter(TheLock);
}
public void Dispose()
{
Monitor.Exit(TheLock);
LOG.TraceLock("UNLOCKED " + Name);
}
}