您将如何简化输入和退出ReaderWriterLock?

这对我来说似乎很吵。 五行开销太多了。

m_Lock.EnterReadLock() Try Return m_List.Count Finally m_Lock.ExitReadLock() End Try 

那你怎么这么简单呢?

我的想法是一样的,但在C#;-p

 using System; using System.Threading; class Program { static void Main() { ReaderWriterLockSlim sync = new ReaderWriterLockSlim(); using (sync.Read()) { // etc } } } public static class ReaderWriterExt { sealed class ReadLockToken : IDisposable { private ReaderWriterLockSlim sync; public ReadLockToken(ReaderWriterLockSlim sync) { this.sync = sync; sync.EnterReadLock(); } public void Dispose() { if (sync != null) { sync.ExitReadLock(); sync = null; } } } public static IDisposable Read(this ReaderWriterLockSlim obj) { return new ReadLockToken(obj); } } 

到目前为止发布的所有解决方案都存在死锁风险。 像这样的使用块:

 ReaderWriterLockSlim sync = new ReaderWriterLockSlim(); using (sync.Read()) { // Do stuff } 

转换成这样的东西:

 ReaderWriterLockSlim sync = new ReaderWriterLockSlim(); IDisposable d = sync.Read(); try { // Do stuff } finally { d.Dispose(); } 

这意味着在sync.Read()和try块之间可能发生ThreadAbortException(或类似)。 当发生这种情况时,finally块永远不会被调用,并且锁永远不会释放!

有关更多信息和更好的实现,请参阅: 使用ReaderWriterLockSlim和其他锁定对象的死锁

此外,来自Joe Duffy的博客

接下来,锁对于异步exception(例如线程中止和内存不足情况)不稳健。 如果其中一个发生在其中一个锁定方法的中间,则锁定状态可能会损坏,导致后续死锁,未处理的exception,并且(遗憾地)由于内部使用自旋锁,一个挂钩的100%CPU。 因此,如果您要在一个经常使用线程中止或尝试在硬OOM中存活的环境中运行代码,那么您将不会对此锁定感到满意。

这不是我的发明,但它确实使头发变得不那么灰了。

 internal static class ReaderWriteLockExtensions { private struct Disposable : IDisposable { private readonly Action m_action; private Sentinel m_sentinel; public Disposable(Action action) { m_action = action; m_sentinel = new Sentinel(); } public void Dispose() { m_action(); GC.SuppressFinalize(m_sentinel); } } private class Sentinel { ~Sentinel() { throw new InvalidOperationException("Lock not properly disposed."); } } public static IDisposable AcquireReadLock(this ReaderWriterLockSlim lock) { lock.EnterReadLock(); return new Disposable(lock.ExitReadLock); } public static IDisposable AcquireUpgradableReadLock(this ReaderWriterLockSlim lock) { lock.EnterUpgradeableReadLock(); return new Disposable(lock.ExitUpgradeableReadLock); } public static IDisposable AcquireWriteLock(this ReaderWriterLockSlim lock) { lock.EnterWriteLock(); return new Disposable(lock.ExitWriteLock); } } 

如何使用:

 using (m_lock.AcquireReadLock()) { // Do stuff } 

我最终做到了这一点,但我仍然对我设计中更好的方法或缺陷持开放态度。

 Using m_Lock.ReadSection Return m_List.Count End Using 

这使用了这个扩展方法/类:

  Public Function ReadSection(ByVal lock As ReaderWriterLockSlim) As ReadWrapper Return New ReadWrapper(lock) End Function Public NotInheritable Class ReadWrapper Implements IDisposable Private m_Lock As ReaderWriterLockSlim Public Sub New(ByVal lock As ReaderWriterLockSlim) m_Lock = lock m_Lock.EnterReadLock() End Sub Public Sub Dispose() Implements IDisposable.Dispose m_Lock.ExitReadLock() End Sub End Class 

由于锁定点是为了保护某些内存,我认为将该内存包装在“Locked”对象中是有用的,并且只能通过各种锁定令牌进行访问(如Mark所述 ):

 // Stores a private List, only accessible through lock tokens // returned by Read, Write, and UpgradableRead. var lockedList = new LockedList( ); 
 using( var r = lockedList.Read( ) ) { foreach( T item in r.Reader ) ... } 
 using( var w = lockedList.Write( ) ) { w.Writer.Add( new T( ) ); } 
 T t = ...; using( var u = lockedList.UpgradableRead( ) ) { if( !u.Reader.Contains( t ) ) using( var w = u.Upgrade( ) ) w.Writer.Add( t ); } 

现在访问内部列表的唯一方法是调用适当的访问器。

这对List特别ReadOnlyCollection ,因为它已经有ReadOnlyCollection包装器。 对于其他类型,你总是可以创建一个Locked ,但是你会失去可读/可写的好区别。

一种改进可能是将RW类型定义为一次性包装器本身,这将防止(无意)错误,如:

 List list; using( var w = lockedList.Write( ) ) list = w.Writable; //BAD: "locked" object leaked outside of lock scope list.MakeChangesWithoutHoldingLock( ); 

但是,这会使Locked使用起来更加复杂,并且当前版本确实为您提供了手动锁定共享成员时的相同保护。


 sealed class LockedList : Locked, ReadOnlyCollection> { public LockedList( ) : base( new List( ), list => list.AsReadOnly( ) ) { } } public class Locked where W : class where R : class { private readonly LockerState state_; public Locked( W writer, R reader ) { this.state_ = new LockerState( reader, writer ); } public Locked( W writer, Func getReader ) : this( writer, getReader( writer ) ) { } public IReadable Read( ) { return new Readable( this.state_ ); } public IWritable Write( ) { return new Writable( this.state_ ); } public IUpgradable UpgradableRead( ) { return new Upgradable( this.state_ ); } public interface IReadable : IDisposable { R Reader { get; } } public interface IWritable : IDisposable { W Writer { get; } } public interface IUpgradable : IReadable { IWritable Upgrade( );} #region Private Implementation Details sealed class LockerState { public readonly R Reader; public readonly W Writer; public readonly ReaderWriterLockSlim Sync; public LockerState( R reader, W writer ) { Debug.Assert( reader != null && writer != null ); this.Reader = reader; this.Writer = writer; this.Sync = new ReaderWriterLockSlim( ); } } abstract class Accessor : IDisposable { private LockerState state_; protected LockerState State { get { return this.state_; } } protected Accessor( LockerState state ) { Debug.Assert( state != null ); this.Acquire( state.Sync ); this.state_ = state; } protected abstract void Acquire( ReaderWriterLockSlim sync ); protected abstract void Release( ReaderWriterLockSlim sync ); public void Dispose( ) { if( this.state_ != null ) { var sync = this.state_.Sync; this.state_ = null; this.Release( sync ); } } } class Readable : Accessor, IReadable { public Readable( LockerState state ) : base( state ) { } public R Reader { get { return this.State.Reader; } } protected override void Acquire( ReaderWriterLockSlim sync ) { sync.EnterReadLock( ); } protected override void Release( ReaderWriterLockSlim sync ) { sync.ExitReadLock( ); } } sealed class Writable : Accessor, IWritable { public Writable( LockerState state ) : base( state ) { } public W Writer { get { return this.State.Writer; } } protected override void Acquire( ReaderWriterLockSlim sync ) { sync.EnterWriteLock( ); } protected override void Release( ReaderWriterLockSlim sync ) { sync.ExitWriteLock( ); } } sealed class Upgradable : Readable, IUpgradable { public Upgradable( LockerState state ) : base( state ) { } public IWritable Upgrade( ) { return new Writable( this.State ); } protected override void Acquire( ReaderWriterLockSlim sync ) { sync.EnterUpgradeableReadLock( ); } protected override void Release( ReaderWriterLockSlim sync ) { sync.ExitUpgradeableReadLock( ); } } #endregion }