DotNext by .NET Foundation and Contributors

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

 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.Diagnostics; using System.Diagnostics.CodeAnalysis; 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> { internal enum Type : byte { None, Monitor, ReadLock, UpgradeableReadLock, WriteLock, Semaphore } [StructLayout(LayoutKind.Auto)] [System.Runtime.CompilerServices.NullableContext(0)] public ref struct Holder { private readonly object lockedObject; private readonly Type type; public bool IsEmpty { [IsReadOnly] get { return lockedObject == null; } } 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 implicit operator bool([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] [Conditional("DEBUG")] private void AssertLockType() { switch (type) { } } [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] private bool Equals([In] [IsReadOnly] ref Lock other) { if (type == other.type && lockedObject == other.lockedObject) return owner == other.owner; return false; } [IsReadOnly] public bool Equals(Lock other) { return Equals(ref other); } [IsReadOnly] [System.Runtime.CompilerServices.NullableContext(2)] public override bool Equals([NotNullWhen(true)] object other) { if (other is Lock) { Lock other2 = (Lock)other; return Equals(ref 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) { return first.Equals(ref second); } public static bool operator !=([In] [IsReadOnly] ref Lock first, [In] [IsReadOnly] ref Lock second) { return !first.Equals(ref second); } } }