Question

Cela me semble très bruyant. Cinq lignes de frais généraux, c'est trop.

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

Alors, comment voulez-vous simplement cela?

Était-ce utile?

La solution

Je pensais la même chose, mais en 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);
    }
}

Autres conseils

Toutes les solutions publiées jusqu’à présent risquent d’être bloquées. Un bloc using comme ceci:

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

est converti en quelque chose comme ceci:

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

Cela signifie qu'une exception ThreadAbortException (ou similaire) pourrait se produire entre sync.Read () et le bloc try. Lorsque cela se produit, le bloc finally n'est jamais appelé et le verrou n'est jamais libéré!

Pour plus d'informations et une meilleure mise en œuvre, voir: Deadlock avec ReaderWriterLockSlim et d'autres objets de verrouillage

Voir aussi, à partir de le blog de Joe Duff / a>

  

Ensuite, le verrou n'est pas robuste aux exceptions asynchrones telles que les abandons de threads et les conditions de mémoire insuffisante. Si l’une de ces méthodes survient alors qu’elle est au milieu d’une des méthodes du verrou & # 8217; s, son état de verrouillage peut être corrompu, ce qui entraîne des blocages ultérieurs, des exceptions non gérées et (malheureusement) en raison de l’utilisation de verrous de rotation en interne. un 100% CPU bloqué. Ainsi, si vous & # 8217; exécutez votre code dans un environnement qui utilise régulièrement des abandons de threads ou tente de survivre à des MOO durs, vous ne serez & # 8217; pas satisfait de ce verrou.

Ce n’est pas mon invention, mais c’est certainement fait par les cheveux un peu moins gris.

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

Comment utiliser:

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

J'ai fini par le faire, mais je suis toujours ouvert à de meilleures façons ou défauts dans ma conception.

Using m_Lock.ReadSection
    Return m_List.Count
End Using

Ceci utilise cette méthode / classe d'extension:

<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

Comme le but d'un verrou est de protéger une partie de la mémoire, je pense qu'il serait utile d'envelopper cette mémoire dans un & "Locked &"; objet, et ne le rendre accessible que par les différents jetons de verrouillage (comme mentionné par Mark ):

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

Désormais, le seul moyen d'accéder à la liste interne consiste à appeler l'accesseur approprié.

Cela fonctionne particulièrement bien pour List<T>, car il dispose déjà du wrapper ReadOnlyCollection<T>. Pour les autres types, vous pouvez toujours créer un Locked<T,T>, mais vous perdez la distinction entre les types lisible / inscriptible.

Une amélioration pourrait consister à définir les types R et W comme des enveloppes jetables elles-mêmes, qui seraient protégées contre les erreurs (par inadvertance) telles que:

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

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

Toutefois, cela rendrait Locked l'utilisation plus compliquée, et la version actuelle vous offre la même protection que celle que vous avez lorsque vous verrouillez manuellement un membre partagé.

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
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top