using System; using System.Threading; using Unosquare.Swan.Abstractions; namespace Unosquare.Swan.Components { /// /// Provides factory methods to create synchronized reader-writer locks /// that support a generalized locking and releasing api and syntax. /// public static class SyncLockerFactory { #region Enums and Interfaces /// /// Enumerates the locking operations. /// private enum LockHolderType { Read, Write, } /// /// Defines methods for releasing locks. /// private interface ISyncReleasable { /// /// Releases the writer lock. /// void ReleaseWriterLock(); /// /// Releases the reader lock. /// void ReleaseReaderLock(); } #endregion #region Factory Methods #if !NETSTANDARD1_3 /// /// Creates a reader-writer lock backed by a standard ReaderWriterLock. /// /// The synchronized locker. public static ISyncLocker Create() => new SyncLocker(); #else /// /// Creates a reader-writer lock backed by a standard ReaderWriterLockSlim when /// running at NETSTANDARD 1.3. /// /// The synchronized locker public static ISyncLocker Create() => new SyncLockerSlim(); #endif /// /// Creates a reader-writer lock backed by a ReaderWriterLockSlim. /// /// The synchronized locker. public static ISyncLocker CreateSlim() => new SyncLockerSlim(); /// /// Creates a reader-writer lock. /// /// if set to true it uses the Slim version of a reader-writer lock. /// The Sync Locker. public static ISyncLocker Create(Boolean useSlim) => useSlim ? CreateSlim() : Create(); #endregion #region Private Classes /// /// The lock releaser. Calling the dispose method releases the lock entered by the parent SyncLocker. /// /// private sealed class SyncLockReleaser : IDisposable { private readonly ISyncReleasable _parent; private readonly LockHolderType _operation; private Boolean _isDisposed; /// /// Initializes a new instance of the class. /// /// The parent. /// The operation. public SyncLockReleaser(ISyncReleasable parent, LockHolderType operation) { this._parent = parent; this._operation = operation; } /// public void Dispose() { if(this._isDisposed) { return; } this._isDisposed = true; if(this._operation == LockHolderType.Read) { this._parent.ReleaseReaderLock(); } else { this._parent.ReleaseWriterLock(); } } } #if !NETSTANDARD1_3 /// /// The Sync Locker backed by a ReaderWriterLock. /// /// /// private sealed class SyncLocker : ISyncLocker, ISyncReleasable { private Boolean _isDisposed; private ReaderWriterLock _locker = new ReaderWriterLock(); /// public IDisposable AcquireReaderLock() { this._locker?.AcquireReaderLock(Timeout.Infinite); return new SyncLockReleaser(this, LockHolderType.Read); } /// public IDisposable AcquireWriterLock() { this._locker?.AcquireWriterLock(Timeout.Infinite); return new SyncLockReleaser(this, LockHolderType.Write); } /// public void ReleaseWriterLock() => this._locker?.ReleaseWriterLock(); /// public void ReleaseReaderLock() => this._locker?.ReleaseReaderLock(); /// public void Dispose() { if(this._isDisposed) { return; } this._isDisposed = true; _ = this._locker?.ReleaseLock(); this._locker = null; } } #endif /// /// The Sync Locker backed by ReaderWriterLockSlim. /// /// /// private sealed class SyncLockerSlim : ISyncLocker, ISyncReleasable { private Boolean _isDisposed; private ReaderWriterLockSlim _locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); /// public IDisposable AcquireReaderLock() { this._locker?.EnterReadLock(); return new SyncLockReleaser(this, LockHolderType.Read); } /// public IDisposable AcquireWriterLock() { this._locker?.EnterWriteLock(); return new SyncLockReleaser(this, LockHolderType.Write); } /// public void ReleaseWriterLock() => this._locker?.ExitWriteLock(); /// public void ReleaseReaderLock() => this._locker?.ExitReadLock(); /// public void Dispose() { if(this._isDisposed) { return; } this._isDisposed = true; this._locker?.Dispose(); this._locker = null; } } #endregion } }