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