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