DotNext by Roman Sakno

<PackageReference Include="DotNext" Version="0.11.1" />

 Lock

public struct Lock : IDisposable, IEquatable<Lock>
Unified representation of monitor lock, semaphore lock, read lock, write lock or upgradeable read lock.
using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; namespace DotNext.Threading { public struct Lock : IDisposable, IEquatable<Lock> { internal enum Type : byte { None, Monitor, ReadLock, UpgradeableReadLock, WriteLock, Semaphore } public struct Holder : IDisposable { 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] [System.Runtime.CompilerServices.IsReadOnly] ref Holder holder) { return holder.lockedObject != null; } public static bool operator false([In] [System.Runtime.CompilerServices.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); } 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); } 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; } } public bool TryAcquire(out Holder holder) { if (TryAcquire()) { holder = new Holder(lockedObject, type); return true; } holder = default(Holder); return false; } 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; } } public bool TryAcquire(TimeSpan timeout, out Holder holder) { if (TryAcquire(timeout)) { holder = new Holder(lockedObject, type); return true; } holder = default(Holder); return false; } 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); } public bool Equals(Lock other) { if (type == other.type && lockedObject == other.lockedObject) return owner == other.owner; return false; } public override bool Equals(object other) { if (other is Lock) { Lock other2 = (Lock)other; return Equals(other2); } return false; } public override int GetHashCode() { if (lockedObject == null) return 0; return ((-549183179 * -1521134295 + lockedObject.GetHashCode()) * -1521134295 + type.GetHashCode()) * -1521134295 + owner.GetHashCode(); } public override string ToString() { return type.ToString(); } public static bool operator ==([In] [System.Runtime.CompilerServices.IsReadOnly] ref Lock first, [In] [System.Runtime.CompilerServices.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] [System.Runtime.CompilerServices.IsReadOnly] ref Lock first, [In] [System.Runtime.CompilerServices.IsReadOnly] ref Lock second) { if (first.lockedObject == second.lockedObject && first.type == second.type) return first.owner != second.owner; return true; } } }