You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
93 lines
2.5 KiB
93 lines
2.5 KiB
1 year ago
|
namespace StabilityMatrix.Core.Helper;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Extended <see cref="ReaderWriterLockSlim"/> with support for disposal pattern.
|
||
|
/// </summary>
|
||
|
public class ReaderWriterLockAdvanced : ReaderWriterLockSlim
|
||
|
{
|
||
|
public ReaderWriterLockAdvanced()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public ReaderWriterLockAdvanced(LockRecursionPolicy recursionPolicy) : base(recursionPolicy)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public DisposableLock EnterReadContext(TimeSpan timeout = default)
|
||
|
{
|
||
|
if (!TryEnterReadLock(timeout))
|
||
|
{
|
||
|
throw new TimeoutException("Timeout waiting for read lock");
|
||
|
}
|
||
|
return new DisposableLock(this, LockType.Read);
|
||
|
}
|
||
|
|
||
|
public DisposableLock EnterWriteContext(TimeSpan timeout = default)
|
||
|
{
|
||
|
if (!TryEnterWriteLock(timeout))
|
||
|
{
|
||
|
throw new TimeoutException("Timeout waiting for write lock");
|
||
|
}
|
||
|
return new DisposableLock(this, LockType.Write);
|
||
|
}
|
||
|
|
||
|
public DisposableLock EnterUpgradeableReadContext(TimeSpan timeout = default)
|
||
|
{
|
||
|
if (!TryEnterUpgradeableReadLock(timeout))
|
||
|
{
|
||
|
throw new TimeoutException("Timeout waiting for upgradeable read lock");
|
||
|
}
|
||
|
return new DisposableLock(this, LockType.UpgradeableRead);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Wrapper for disposable lock
|
||
|
/// </summary>
|
||
|
public class DisposableLock : IDisposable
|
||
|
{
|
||
|
private readonly ReaderWriterLockAdvanced readerWriterLock;
|
||
|
private readonly LockType lockType;
|
||
|
|
||
|
public DisposableLock(ReaderWriterLockAdvanced @lock, LockType lockType)
|
||
|
{
|
||
|
readerWriterLock = @lock;
|
||
|
this.lockType = lockType;
|
||
|
}
|
||
|
|
||
|
public DisposableLock UpgradeToWrite(TimeSpan timeout = default)
|
||
|
{
|
||
|
if (lockType != LockType.UpgradeableRead)
|
||
|
{
|
||
|
throw new InvalidOperationException("Can only upgrade from upgradeable read lock");
|
||
|
}
|
||
|
return readerWriterLock.EnterWriteContext(timeout);
|
||
|
}
|
||
|
|
||
|
public void Dispose()
|
||
|
{
|
||
|
switch (lockType)
|
||
|
{
|
||
|
case LockType.Read:
|
||
|
readerWriterLock.ExitReadLock();
|
||
|
break;
|
||
|
case LockType.Write:
|
||
|
readerWriterLock.ExitWriteLock();
|
||
|
break;
|
||
|
case LockType.UpgradeableRead:
|
||
|
readerWriterLock.ExitUpgradeableReadLock();
|
||
|
break;
|
||
|
default:
|
||
|
throw new ArgumentOutOfRangeException();
|
||
|
}
|
||
|
GC.SuppressFinalize(this);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public enum LockType
|
||
|
{
|
||
|
Read,
|
||
|
Write,
|
||
|
UpgradeableRead
|
||
|
}
|