对于非高性能锁定......只是健壮的线程安全代码......我想要简单的lock (obj) { code; }
,但我想在它之前和之后记录(这样我可以通过获取来自用户的日志),我想支持 ReaderWriterLocks。(是的,我意识到 Monitor 和 SpinLock 等更快......但这不是高性能的高线程数......速度在这里不是问题。)
我已经看到了通过 执行此操作的建议using (new ReadLock(myLock)) { code; }
,但是经常怀疑新类的编码。
Sooo,这就是我想出的。我对你们所有人的问题:(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);
}
}