1

高性能ではないロックの場合...堅牢なスレッドセーフコードだけ...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);
    }
}
4

0 に答える 0