DotNext by .NET Foundation and Contributors

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

 Atomic<T>

public struct Atomic<T> : IStrongBox, ICloneable where T : struct
Provides atomic access to non-primitive data type.
using DotNext.Runtime; using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; namespace DotNext.Threading { [StructLayout(LayoutKind.Auto)] public struct Atomic<T> : IStrongBox, ICloneable where T : struct { private interface IEqualityComparer { bool Equals([In] [IsReadOnly] T x, [In] [IsReadOnly] T y); } [StructLayout(LayoutKind.Auto)] private readonly struct BitwiseEqualityComparer : IEqualityComparer { bool IEqualityComparer.Equals([In] [IsReadOnly] T x, [In] [IsReadOnly] T y) { return BitwiseComparer<T>.Equals(ref x, ref y); } } [StructLayout(LayoutKind.Auto)] private readonly struct DelegatingEqualityComparer : IEqualityComparer { [System.Runtime.CompilerServices.Nullable(new byte[] { 1, 0, 0 })] private readonly Func<T, T, bool> func; internal DelegatingEqualityComparer([System.Runtime.CompilerServices.Nullable(new byte[] { 1, 0, 0 })] Func<T, T, bool> func) { if (func == null) throw new ArgumentNullException("func"); this.func = func; } bool IEqualityComparer.Equals([In] [IsReadOnly] T x, [In] [IsReadOnly] T y) { return func(x, y); } } [StructLayout(LayoutKind.Auto)] private readonly struct EqualityComparer : IEqualityComparer { private readonly IntPtr ptr; internal unsafe EqualityComparer(IntPtr ptr) { if (ptr == (IntPtr)(void*)null) throw new ArgumentNullException("ptr"); this.ptr = ptr; } bool IEqualityComparer.Equals([In] [IsReadOnly] T x, [In] [IsReadOnly] T y) { IntPtr intPtr = ptr; return (byte) != 0; } } public delegate void Updater (ref T current); public delegate void Accumulator (ref T current, [In] [IsReadOnly] T x); private T value; private AtomicBoolean lockState; private volatile int version; public T Value { [IsReadOnly] get { Read(out T result); return result; } set { Write(ref value); } } [System.Runtime.CompilerServices.Nullable(2)] object IStrongBox.Value { [IsReadOnly] [System.Runtime.CompilerServices.NullableContext(2)] get { return Value; } [System.Runtime.CompilerServices.NullableContext(2)] set { Value = (T)value; } } public Atomic<T> Clone() { Atomic<T> result = default(Atomic<T>); Read(out result.value); return result; } [System.Runtime.CompilerServices.NullableContext(1)] object ICloneable.Clone() { return Clone(); } [IsReadOnly] public void Read(out T result) { SpinWait spinWait = default(SpinWait); while (true) { int num = version; Intrinsics.Copy<T>(ref value, out result); if (num == version && !lockState.Value) break; spinWait.SpinOnce(); } } public void Swap(ref Atomic<T> other) { lockState.Acquire(); Interlocked.Increment(ref version); Swap(ref other.value); lockState.Release(); } public void Swap(ref T other) { lockState.Acquire(); Interlocked.Increment(ref version); Intrinsics.Swap<T>(ref value, ref other); lockState.Release(); } public void Write([In] [IsReadOnly] ref T newValue) { lockState.Acquire(); Interlocked.Increment(ref version); Intrinsics.Copy<T>(ref newValue, out value); lockState.Release(); } private bool CompareExchange<TComparer>(TComparer comparer, [In] [IsReadOnly] ref T update, [In] [IsReadOnly] ref T expected, out T result) where TComparer : struct, IEqualityComparer { this.lockState.Acquire(); Interlocked.Increment(ref this.version); T x = this.value; bool num = ((IEqualityComparer)comparer).Equals(ref x, ref expected); if (num) Intrinsics.Copy<T>(ref update, out this.value); Intrinsics.Copy<T>(ref x, out result); this.lockState.Release(); return num; } public bool CompareExchange([In] [IsReadOnly] ref T update, [In] [IsReadOnly] ref T expected, out T result) { return CompareExchange(default(BitwiseEqualityComparer), ref update, ref expected, out result); } public bool CompareExchange([System.Runtime.CompilerServices.Nullable(new byte[] { 1, 0, 0 })] Func<T, T, bool> comparer, [In] [IsReadOnly] ref T update, [In] [IsReadOnly] ref T expected, out T result) { return CompareExchange(new DelegatingEqualityComparer(comparer), ref update, ref expected, out result); } [CLSCompliant(false)] public bool CompareExchange(IntPtr comparer, [In] [IsReadOnly] ref T update, [In] [IsReadOnly] ref T expected, out T result) { return CompareExchange(new EqualityComparer(comparer), ref update, ref expected, out result); } private bool CompareAndSet<TComparer>(TComparer comparer, [In] [IsReadOnly] ref T expected, [In] [IsReadOnly] ref T update) where TComparer : struct, IEqualityComparer { this.lockState.Acquire(); Interlocked.Increment(ref this.version); bool num = ((IEqualityComparer)comparer).Equals(ref this.value, ref expected); if (num) Intrinsics.Copy<T>(ref update, out this.value); this.lockState.Release(); return num; } public bool CompareAndSet([In] [IsReadOnly] ref T expected, [In] [IsReadOnly] ref T update) { return CompareAndSet(default(BitwiseEqualityComparer), ref expected, ref update); } public bool CompareAndSet([System.Runtime.CompilerServices.Nullable(new byte[] { 1, 0, 0 })] Func<T, T, bool> comparer, [In] [IsReadOnly] ref T expected, [In] [IsReadOnly] ref T update) { return CompareAndSet(new DelegatingEqualityComparer(comparer), ref expected, ref update); } [CLSCompliant(false)] public bool CompareAndSet(IntPtr comparer, [In] [IsReadOnly] ref T expected, [In] [IsReadOnly] ref T update) { return CompareAndSet(new EqualityComparer(comparer), ref expected, ref update); } public void Exchange([In] [IsReadOnly] ref T update, out T previous) { lockState.Acquire(); Interlocked.Increment(ref version); Intrinsics.Copy<T>(ref value, out previous); Intrinsics.Copy<T>(ref update, out value); lockState.Release(); } public void UpdateAndGet([System.Runtime.CompilerServices.Nullable(new byte[] { 1, 0 })] Updater updater, out T result) { if (updater == null) throw new ArgumentNullException("updater"); lockState.Acquire(); Interlocked.Increment(ref version); try { updater(ref value); Intrinsics.Copy<T>(ref value, out result); } finally { lockState.Release(); } } public void GetAndUpdate([System.Runtime.CompilerServices.Nullable(new byte[] { 1, 0 })] Updater updater, out T result) { if (updater == null) throw new ArgumentNullException("updater"); lockState.Acquire(); Interlocked.Increment(ref version); T input = value; try { updater(ref value); Intrinsics.Copy<T>(ref input, out result); } finally { lockState.Release(); } } public void AccumulateAndGet([In] [IsReadOnly] ref T x, [System.Runtime.CompilerServices.Nullable(new byte[] { 1, 0 })] Accumulator accumulator, out T result) { if (accumulator == null) throw new ArgumentNullException("accumulator"); lockState.Acquire(); Interlocked.Increment(ref version); try { accumulator(ref value, ref x); Intrinsics.Copy<T>(ref value, out result); } finally { lockState.Release(); } } public void GetAndAccumulate([In] [IsReadOnly] ref T x, [System.Runtime.CompilerServices.Nullable(new byte[] { 1, 0 })] Accumulator accumulator, out T result) { if (accumulator == null) throw new ArgumentNullException("accumulator"); lockState.Acquire(); Interlocked.Increment(ref version); T input = value; try { accumulator(ref value, ref x); Intrinsics.Copy<T>(ref input, out result); } finally { lockState.Release(); } } [IsReadOnly] [System.Runtime.CompilerServices.NullableContext(2)] public override string ToString() { Read(out T result); return result.ToString(); } } }