Lock
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
namespace DotNext.Threading
{
[StructLayout(LayoutKind.Auto)]
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public struct Lock : IDisposable, IEquatable<Lock>
{
[System.Runtime.CompilerServices.NullableContext(0)]
internal enum Type : byte
{
None,
Monitor,
ReadLock,
UpgradeableReadLock,
WriteLock,
Semaphore
}
[StructLayout(LayoutKind.Auto)]
[System.Runtime.CompilerServices.Nullable(0)]
public ref struct Holder
{
private readonly object lockedObject;
private readonly Type type;
internal Holder(object lockedObject, Type type)
{
this.lockedObject = lockedObject;
this.type = type;
}
public void Dispose()
{
switch (type) {
case Type.Monitor:
System.Threading.Monitor.Exit(lockedObject);
break;
case Type.ReadLock:
Unsafe.As<ReaderWriterLockSlim>(lockedObject).ExitReadLock();
break;
case Type.WriteLock:
Unsafe.As<ReaderWriterLockSlim>(lockedObject).ExitWriteLock();
break;
case Type.UpgradeableReadLock:
Unsafe.As<ReaderWriterLockSlim>(lockedObject).ExitUpgradeableReadLock();
break;
case Type.Semaphore:
Unsafe.As<SemaphoreSlim>(lockedObject).Release();
break;
}
this = default(Holder);
}
public static bool operator true([In] [IsReadOnly] ref Holder holder)
{
return holder.lockedObject != null;
}
public static bool operator false([In] [IsReadOnly] ref Holder holder)
{
return holder.lockedObject == null;
}
}
private readonly object lockedObject;
private readonly Type type;
private readonly bool owner;
private Lock(object lockedObject, Type type, bool owner)
{
this.lockedObject = lockedObject;
this.type = type;
this.owner = owner;
}
public static Lock Semaphore(SemaphoreSlim semaphore)
{
if (semaphore == null)
throw new ArgumentNullException("semaphore");
return new Lock(semaphore, Type.Semaphore, false);
}
public static Lock Semaphore(int initialCount, int maxCount)
{
return new Lock(new SemaphoreSlim(initialCount, maxCount), Type.Semaphore, true);
}
public static Lock Monitor(object obj)
{
if (obj == null)
throw new ArgumentNullException("obj");
return new Lock(obj, Type.Monitor, false);
}
public static Lock Monitor()
{
return new Lock(new object(), Type.Monitor, true);
}
public static Lock ReadLock(ReaderWriterLockSlim rwLock, bool upgradeable)
{
if (rwLock == null)
throw new ArgumentNullException("rwLock");
return new Lock(rwLock, upgradeable ? Type.UpgradeableReadLock : Type.ReadLock, false);
}
public static Lock WriteLock(ReaderWriterLockSlim rwLock)
{
if (rwLock == null)
throw new ArgumentNullException("rwLock");
return new Lock(rwLock, Type.WriteLock, false);
}
[IsReadOnly]
public Holder Acquire()
{
switch (type) {
case Type.Monitor:
System.Threading.Monitor.Enter(lockedObject);
break;
case Type.ReadLock:
Unsafe.As<ReaderWriterLockSlim>(lockedObject).EnterReadLock();
break;
case Type.WriteLock:
Unsafe.As<ReaderWriterLockSlim>(lockedObject).EnterWriteLock();
break;
case Type.UpgradeableReadLock:
Unsafe.As<ReaderWriterLockSlim>(lockedObject).EnterUpgradeableReadLock();
break;
case Type.Semaphore:
Unsafe.As<SemaphoreSlim>(lockedObject).Wait();
break;
}
return new Holder(lockedObject, type);
}
[IsReadOnly]
private bool TryAcquire()
{
switch (type) {
case Type.Monitor:
return System.Threading.Monitor.TryEnter(lockedObject);
case Type.ReadLock:
return Unsafe.As<ReaderWriterLockSlim>(lockedObject).TryEnterReadLock(0);
case Type.WriteLock:
return Unsafe.As<ReaderWriterLockSlim>(lockedObject).TryEnterWriteLock(0);
case Type.UpgradeableReadLock:
return Unsafe.As<ReaderWriterLockSlim>(lockedObject).TryEnterUpgradeableReadLock(0);
case Type.Semaphore:
return Unsafe.As<SemaphoreSlim>(lockedObject).Wait(0);
default:
return false;
}
}
[IsReadOnly]
public bool TryAcquire(out Holder holder)
{
if (TryAcquire()) {
holder = new Holder(lockedObject, type);
return true;
}
holder = default(Holder);
return false;
}
[IsReadOnly]
private bool TryAcquire(TimeSpan timeout)
{
switch (type) {
case Type.Monitor:
return System.Threading.Monitor.TryEnter(lockedObject, timeout);
case Type.ReadLock:
return Unsafe.As<ReaderWriterLockSlim>(lockedObject).TryEnterReadLock(timeout);
case Type.WriteLock:
return Unsafe.As<ReaderWriterLockSlim>(lockedObject).TryEnterWriteLock(timeout);
case Type.UpgradeableReadLock:
return Unsafe.As<ReaderWriterLockSlim>(lockedObject).TryEnterUpgradeableReadLock(timeout);
case Type.Semaphore:
return Unsafe.As<SemaphoreSlim>(lockedObject).Wait(timeout);
default:
return false;
}
}
[IsReadOnly]
public bool TryAcquire(TimeSpan timeout, out Holder holder)
{
if (TryAcquire(timeout)) {
holder = new Holder(lockedObject, type);
return true;
}
holder = default(Holder);
return false;
}
[IsReadOnly]
public Holder Acquire(TimeSpan timeout)
{
if (!TryAcquire(timeout))
throw new TimeoutException();
return new Holder(lockedObject, type);
}
public void Dispose()
{
if (owner)
(lockedObject as IDisposable)?.Dispose();
this = default(Lock);
}
[IsReadOnly]
public bool Equals(Lock other)
{
if (type == other.type && lockedObject == other.lockedObject)
return owner == other.owner;
return false;
}
[IsReadOnly]
[System.Runtime.CompilerServices.NullableContext(2)]
public override bool Equals(object other)
{
if (other is Lock) {
Lock other2 = (Lock)other;
return Equals(other2);
}
return false;
}
[IsReadOnly]
public override int GetHashCode()
{
return HashCode.Combine(lockedObject, type, owner);
}
[IsReadOnly]
public override string ToString()
{
return type.ToString();
}
public static bool operator ==([In] [IsReadOnly] ref Lock first, [In] [IsReadOnly] ref Lock second)
{
if (first.lockedObject == second.lockedObject && first.type == second.type)
return first.owner == second.owner;
return false;
}
public static bool operator !=([In] [IsReadOnly] ref Lock first, [In] [IsReadOnly] ref Lock second)
{
if (first.lockedObject == second.lockedObject && first.type == second.type)
return first.owner != second.owner;
return true;
}
}
}