Frage

Das scheint mir sehr laut zu sein. Fünf Zeilen Overhead sind einfach zu viel.

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

Wie würdest du das einfach?

War es hilfreich?

Lösung

Ich dachte dasselbe, aber in 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);
    }
}

Andere Tipps

Alle bisher veröffentlichten Lösungen sind dem Risiko eines Deadlocks ausgesetzt. Ein Verwendungsblock wie diesen:

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

wird in so etwas konvertiert:

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

Dies bedeutet, dass eine Threadabortexception (oder eine ähnliche) zwischen Sync.read () und dem Try -Block auftreten kann. Wenn dies passiert, wird der endgültige Block nie angerufen und das Schloss wird nie veröffentlicht!

Weitere Informationen und eine bessere Implementierung finden Sie unter:Deadlock mit ReaderwriterLlockslim und anderen Schließobjekten

Auch von Joe Duffys Blog

Als nächstes ist das Schloss nicht robust gegenüber asynchronen Ausnahmen wie Fadenabbruch und außerhalb der Speicherbedingungen. Wenn einer davon in der Mitte eines der Verriegelungsmethoden auftritt, kann der Schließstatus korrupt sein, was nachfolgenden Sackgassen, unberechtigte Ausnahmen und (leider) aufgrund der Verwendung interner Spinschlösser zu einer 100% igen CPU verursacht. Wenn Sie also Ihren Code in einer Umgebung ausführen, in der regelmäßig Thread -Abbrüche oder Versuche, harte OOMS zu überleben, verwendet, werden Sie mit diesem Schloss nicht zufrieden sein.

Dies ist nicht meine Erfindung, aber es hat sicherlich etwas weniger grau gemacht.

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);
    }
} 

Wie benutzt man:

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

Am Ende habe ich das gemacht, aber ich bin immer noch offen für bessere Wege oder Fehler in meinem Design.

Using m_Lock.ReadSection
    Return m_List.Count
End Using

Dies verwendet diese Erweiterungsmethode/-klasse:

<Extension()> 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

Da es sich um einen Schlossspiegel handelt, um ein Stück Erinnerung zu schützen Markieren):

// Stores a private List<T>, only accessible through lock tokens
//  returned by Read, Write, and UpgradableRead.
var lockedList = new LockedList<T>( );
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 );
}

Die einzige Möglichkeit, auf die interne Liste zuzugreifen, besteht darin, den entsprechenden Accessor aufzurufen.

Dies funktioniert besonders gut für List<T>, da es schon das hat ReadOnlyCollection<T> Verpackung. Für andere Typen könnten Sie immer eine erstellen Locked<T,T>, Aber dann verlieren Sie die nette lesbare/beschreibbare Unterscheidung.

Eine Verbesserung könnte darin bestehen, das zu definieren R und W Typen als Einwegverpackungen selbst, die vor (unbeabsichtigten) Fehlern geschützt würden:

List<T> list;
using( var w = lockedList.Write( ) )
  list = w.Writable;

//BAD: "locked" object leaked outside of lock scope
list.MakeChangesWithoutHoldingLock( );

Dies würde jedoch machen Locked Komplizierter zu bedienen, und die aktuelle Version bietet Ihnen den gleichen Schutz, den Sie haben, wenn Sie ein gemeinsames Mitglied manuell sperren.


sealed class LockedList<T> : Locked<List<T>, ReadOnlyCollection<T>> {
  public LockedList( )
    : base( new List<T>( ), list => list.AsReadOnly( ) )
  { }
}

public class Locked<W, R> 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<W, R> 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
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top