using System;
using System.Threading;
namespace Swan.Threading
{
///
/// 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
///
/// Creates a reader-writer lock backed by a standard ReaderWriterLock.
///
/// The synchronized locker.
public static ISyncLocker Create() => new SyncLocker();
///
/// 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(bool 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 bool _isDisposed;
///
/// Initializes a new instance of the class.
///
/// The parent.
/// The operation.
public SyncLockReleaser(ISyncReleasable parent, LockHolderType operation)
{
_parent = parent;
_operation = operation;
}
///
public void Dispose()
{
if (_isDisposed) return;
_isDisposed = true;
if (_operation == LockHolderType.Read)
_parent.ReleaseReaderLock();
else
_parent.ReleaseWriterLock();
}
}
///
/// The Sync Locker backed by a ReaderWriterLock.
///
///
///
private sealed class SyncLocker : ISyncLocker, ISyncReleasable
{
private bool _isDisposed;
private ReaderWriterLock _locker = new ReaderWriterLock();
///
public IDisposable AcquireReaderLock()
{
_locker?.AcquireReaderLock(Timeout.Infinite);
return new SyncLockReleaser(this, LockHolderType.Read);
}
///
public IDisposable AcquireWriterLock()
{
_locker?.AcquireWriterLock(Timeout.Infinite);
return new SyncLockReleaser(this, LockHolderType.Write);
}
///
public void ReleaseWriterLock() => _locker?.ReleaseWriterLock();
///
public void ReleaseReaderLock() => _locker?.ReleaseReaderLock();
///
public void Dispose()
{
if (_isDisposed) return;
_isDisposed = true;
_locker?.ReleaseLock();
_locker = null;
}
}
///
/// The Sync Locker backed by ReaderWriterLockSlim.
///
///
///
private sealed class SyncLockerSlim : ISyncLocker, ISyncReleasable
{
private bool _isDisposed;
private ReaderWriterLockSlim _locker
= new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
///
public IDisposable AcquireReaderLock()
{
_locker?.EnterReadLock();
return new SyncLockReleaser(this, LockHolderType.Read);
}
///
public IDisposable AcquireWriterLock()
{
_locker?.EnterWriteLock();
return new SyncLockReleaser(this, LockHolderType.Write);
}
///
public void ReleaseWriterLock() => _locker?.ExitWriteLock();
///
public void ReleaseReaderLock() => _locker?.ExitReadLock();
///
public void Dispose()
{
if (_isDisposed) return;
_isDisposed = true;
_locker?.Dispose();
_locker = null;
}
}
#endregion
}
}