How would you simplify Entering and Exiting a ReaderWriterLock?

前端 未结 5 711

This seems very noisy to me. Five lines of overhead is just too much.

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


        
5条回答
  •  暖寄归人
    2020-12-14 12:16

    Since the point of a lock is to protect some piece of memory, I think it would be useful to wrap that memory in a "Locked" object, and only make it accessble through the various lock tokens (as mentioned by 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 );
    }
    

    Now the only way to access the internal list is by calling the appropriate accessor.

    This works particularly well for List, since it already has the ReadOnlyCollection wrapper. For other types, you could always create a Locked, but then you lose out on the nice readable/writable type distinction.

    One improvement might be to define the R and W types as disposable wrappers themselves, which would protected against (inadvertant) errors like:

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

    However, this would make Locked more complicated to use, and the current version does gives you the same protection you have when manually locking a shared member.


    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
    }
    

提交回复
热议问题