ReaderWriterLock을 입력하고 종료하는 방법은 무엇입니까?
-
05-07-2019 - |
문제
이것은 나에게 매우 시끄러운 것 같습니다. 오버 헤드 5 줄은 너무 많습니다.
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 Block 사이에서 ThreadabortException (또는 유사한)이 발생할 수 있음을 의미합니다. 이런 일이 발생하면 마지막으로 블록이 호출되지 않으며 잠금 장치가 해제되지 않습니다!
자세한 내용과 더 나은 구현은 다음을 참조하십시오.ReaderWriterLockSlim 및 기타 잠금 객체와 교착 상태
다음으로, 자물쇠는 스레드 중단 및 메모리 조건과 같은 비동기 예외는 강력하지 않습니다. 이 중 하나가 잠금 방법 중 하나 중 하나에서 발생하는 경우 잠금 상태가 손상되어 내부적으로 스핀 잠금 장치를 사용하여 (슬프게도) 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
이 확장 방법/클래스를 사용합니다.
<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
자물쇠의 지점은 일부 메모리 조각을 보호하는 것이므로, 그 메모리를 "잠긴"객체에 랩핑하고 다양한 잠금 토큰을 통해서만 접근하는 것이 유용 할 것이라고 생각합니다. 표시):
// 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 );
}
이제 내부 목록에 액세스하는 유일한 방법은 적절한 액세서를 호출하는 것입니다.
이것은 특히 잘 작동합니다 List<T>
, 그것은 이미 가지고 있기 때문에 ReadOnlyCollection<T>
싸개. 다른 유형의 경우 항상 a를 만들 수 있습니다 Locked<T,T>
, 그러나, 당신은 멋진 읽기 가능한/쓰기 가능한 유형의 구별을 잃습니다.
한 가지 개선은 정의하는 것입니다 R
그리고 W
일회용 포장지 자체로 유형은 다음과 같은 (비유 적) 오류로부터 보호됩니다.
List<T> list;
using( var w = lockedList.Write( ) )
list = w.Writable;
//BAD: "locked" object leaked outside of lock scope
list.MakeChangesWithoutHoldingLock( );
그러나 이것은 만들어 질 것입니다 Locked
사용하기가 더 복잡하고 현재 버전은 공유 멤버를 수동으로 잠글 때와 동일한 보호 기능을 제공합니다.
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
}