Last active
June 30, 2024 22:08
-
-
Save msx752/185b08bc689109ce37d9cd226aee3daa to your computer and use it in GitHub Desktop.
experimental c# atomiclock
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using BenchmarkDotNet.Attributes; | |
namespace Extendlocked | |
{ | |
public class AtomicBenchmark | |
{ | |
#region Increment | |
[Benchmark] | |
public void IncrementByte() | |
{ | |
byte counter = 0; | |
InterlockedEx.Increment(ref counter); | |
} | |
[Benchmark] | |
public void IncrementInt() | |
{ | |
int counter = 0; | |
InterlockedEx.Increment(ref counter); | |
} | |
[Benchmark] | |
public void IncrementLong() | |
{ | |
long counter = 0; | |
InterlockedEx.Increment(ref counter); | |
} | |
[Benchmark] | |
public void IncrementSByte() | |
{ | |
sbyte counter = 0; | |
InterlockedEx.Increment(ref counter); | |
} | |
[Benchmark] | |
public void IncrementShort() | |
{ | |
short counter = 0; | |
InterlockedEx.Increment(ref counter); | |
} | |
[Benchmark] | |
public void IncrementUInt() | |
{ | |
uint counter = 0; | |
InterlockedEx.Increment(ref counter); | |
} | |
[Benchmark] | |
public void IncrementULong() | |
{ | |
ulong counter = 0; | |
InterlockedEx.Increment(ref counter); | |
} | |
[Benchmark] | |
public void IncrementUShort() | |
{ | |
ushort counter = 0; | |
InterlockedEx.Increment(ref counter); | |
} | |
#endregion Increment | |
#region Decrement | |
[Benchmark] | |
public void DecrementByte() | |
{ | |
byte counter = 1; | |
InterlockedEx.Decrement(ref counter); | |
} | |
[Benchmark] | |
public void DecrementInt() | |
{ | |
int counter = 1; | |
InterlockedEx.Decrement(ref counter); | |
} | |
[Benchmark] | |
public void DecrementLong() | |
{ | |
long counter = 1; | |
InterlockedEx.Decrement(ref counter); | |
} | |
[Benchmark] | |
public void DecrementSByte() | |
{ | |
sbyte counter = 1; | |
InterlockedEx.Decrement(ref counter); | |
} | |
[Benchmark] | |
public void DecrementShort() | |
{ | |
short counter = 1; | |
InterlockedEx.Decrement(ref counter); | |
} | |
[Benchmark] | |
public void DecrementUInt() | |
{ | |
uint counter = 1; | |
InterlockedEx.Decrement(ref counter); | |
} | |
[Benchmark] | |
public void DecrementULong() | |
{ | |
ulong counter = 1; | |
InterlockedEx.Decrement(ref counter); | |
} | |
[Benchmark] | |
public void DecrementUShort() | |
{ | |
ushort counter = 1; | |
InterlockedEx.Decrement(ref counter); | |
} | |
#endregion Decrement | |
#region Read | |
[Benchmark] | |
public void ReadByte() | |
{ | |
byte counter = 1; | |
InterlockedEx.Read(ref counter); | |
} | |
[Benchmark] | |
public void ReadDouble() | |
{ | |
double counter = 1; | |
InterlockedEx.Read(ref counter); | |
} | |
[Benchmark] | |
public void ReadFloat() | |
{ | |
float counter = 1; | |
InterlockedEx.Read(ref counter); | |
} | |
[Benchmark] | |
public void ReadInt() | |
{ | |
int counter = 1; | |
InterlockedEx.Read(ref counter); | |
} | |
[Benchmark] | |
public void ReadLong() | |
{ | |
long counter = 1; | |
InterlockedEx.Read(ref counter); | |
} | |
[Benchmark] | |
public void ReadSByte() | |
{ | |
sbyte counter = 1; | |
InterlockedEx.Read(ref counter); | |
} | |
[Benchmark] | |
public void ReadShort() | |
{ | |
short counter = 1; | |
InterlockedEx.Read(ref counter); | |
} | |
[Benchmark] | |
public void ReadUInt() | |
{ | |
uint counter = 1; | |
InterlockedEx.Read(ref counter); | |
} | |
[Benchmark] | |
public void ReadULong() | |
{ | |
ulong counter = 1; | |
InterlockedEx.Read(ref counter); | |
} | |
[Benchmark] | |
public void ReadUShort() | |
{ | |
ushort counter = 1; | |
InterlockedEx.Read(ref counter); | |
} | |
#endregion Read | |
#region Write | |
[Benchmark] | |
public void WriteByte() | |
{ | |
byte counter = 1; | |
InterlockedEx.Write(ref counter, 3); | |
} | |
[Benchmark] | |
public void WriteDouble() | |
{ | |
double counter = 1; | |
InterlockedEx.Write(ref counter, 3); | |
} | |
[Benchmark] | |
public void WriteFloat() | |
{ | |
float counter = 1; | |
InterlockedEx.Write(ref counter, 3); | |
} | |
[Benchmark] | |
public void WriteInt() | |
{ | |
int counter = 1; | |
InterlockedEx.Write(ref counter, 3); | |
} | |
[Benchmark] | |
public void WriteLong() | |
{ | |
long counter = 1; | |
InterlockedEx.Write(ref counter, 3); | |
} | |
[Benchmark] | |
public void WriteSByte() | |
{ | |
sbyte counter = 1; | |
InterlockedEx.Write(ref counter, 3); | |
} | |
[Benchmark] | |
public void WriteShort() | |
{ | |
short counter = 1; | |
InterlockedEx.Write(ref counter, 3); | |
} | |
[Benchmark] | |
public void WriteUInt() | |
{ | |
uint counter = 1; | |
InterlockedEx.Write(ref counter, 3); | |
} | |
[Benchmark] | |
public void WriteULong() | |
{ | |
ulong counter = 1; | |
InterlockedEx.Write(ref counter, 3); | |
} | |
[Benchmark] | |
public void WriteUShort() | |
{ | |
ushort counter = 1; | |
InterlockedEx.Write(ref counter, 3); | |
} | |
#endregion Write | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Threading; | |
namespace Extendlocked | |
{ | |
public static class InterlockedEx | |
{ | |
#region Exchange | |
public static T Exchange<T>(ref T obj, Func<T, T> func) | |
{ | |
if (func == null) | |
throw new NullReferenceException(nameof(func)); | |
Thread.MemoryBarrier(); | |
obj = func(obj); | |
return obj; | |
} | |
#endregion Exchange | |
#region CompareExchange | |
public static T CompareExchange<T>(ref T obj, T val, T compared) | |
{ | |
return CompareExchange<T>(ref obj, (oldv) => val, compared); | |
} | |
#endregion CompareExchange | |
#region Decrement 2 | |
public static ulong Decrement(ref ulong obj, int decrementBy) | |
{ | |
ulong result = 0; | |
for (int i = 0; i < decrementBy; i++) | |
result = Interlocked.Decrement(ref obj); | |
return result; | |
} | |
public static long Decrement(ref long obj, int decrementBy) | |
{ | |
long result = 0; | |
for (int i = 0; i < decrementBy; i++) | |
result = Interlocked.Decrement(ref obj); | |
return result; | |
} | |
public static uint Decrement(ref uint obj, int decrementBy) | |
{ | |
uint result = 0; | |
for (int i = 0; i < decrementBy; i++) | |
result = Interlocked.Decrement(ref obj); | |
return result; | |
} | |
public static int Decrement(ref int obj, int decrementBy) | |
{ | |
int result = 0; | |
for (int i = 0; i < decrementBy; i++) | |
result = Interlocked.Decrement(ref obj); | |
return result; | |
} | |
public static sbyte Decrement(ref sbyte obj, byte decrementBy) | |
{ | |
return _InternalDecrementBy(ref obj, decrementBy); | |
} | |
public static byte Decrement(ref byte obj, byte decrementBy) | |
{ | |
return _InternalDecrementBy(ref obj, decrementBy); | |
} | |
public static ushort Decrement(ref ushort obj, ushort decrementBy) | |
{ | |
return _InternalDecrementBy(ref obj, decrementBy); | |
} | |
public static short Decrement(ref short obj, short decrementBy) | |
{ | |
return _InternalDecrementBy(ref obj, decrementBy); | |
} | |
#endregion Decrement 2 | |
#region Decrement 1 | |
public static ulong Decrement(ref ulong obj) | |
{ | |
return Decrement(ref obj, 1); | |
} | |
public static long Decrement(ref long obj) | |
{ | |
return Decrement(ref obj, 1); | |
} | |
public static uint Decrement(ref uint obj) | |
{ | |
return Decrement(ref obj, 1); | |
} | |
public static int Decrement(ref int obj) | |
{ | |
return Decrement(ref obj, 1); | |
} | |
public static sbyte Decrement(ref sbyte obj) | |
{ | |
return Decrement(ref obj, 1); | |
} | |
public static byte Decrement(ref byte obj) | |
{ | |
return Decrement(ref obj, 1); | |
} | |
public static ushort Decrement(ref ushort obj) | |
{ | |
return Decrement(ref obj, 1); | |
} | |
public static short Decrement(ref short obj) | |
{ | |
return Decrement(ref obj, 1); | |
} | |
#endregion Decrement 1 | |
#region Increment 2 | |
public static ulong Increment(ref ulong obj, int incrementBy) | |
{ | |
ulong result = 0; | |
for (int i = 0; i < incrementBy; i++) | |
result = Interlocked.Increment(ref obj); | |
return result; | |
} | |
public static long Increment(ref long obj, int incrementBy) | |
{ | |
long result = 0; | |
for (int i = 0; i < incrementBy; i++) | |
result = Interlocked.Increment(ref obj); | |
return result; | |
} | |
public static uint Increment(ref uint obj, int incrementBy) | |
{ | |
uint result = 0; | |
for (int i = 0; i < incrementBy; i++) | |
result = Interlocked.Increment(ref obj); | |
return result; | |
} | |
public static int Increment(ref int obj, int incrementBy) | |
{ | |
int result = 0; | |
for (int i = 0; i < incrementBy; i++) | |
result = Interlocked.Increment(ref obj); | |
return result; | |
} | |
public static sbyte Increment(ref sbyte obj, sbyte incrementBy) | |
{ | |
return _InternalIncrementBy(ref obj, incrementBy); | |
} | |
public static byte Increment(ref byte obj, byte incrementBy) | |
{ | |
return _InternalIncrementBy(ref obj, incrementBy); | |
} | |
public static ushort Increment(ref ushort obj, int incrementBy) | |
{ | |
return _InternalIncrementBy(ref obj, incrementBy); | |
} | |
public static short Increment(ref short obj, int incrementBy) | |
{ | |
return _InternalIncrementBy(ref obj, incrementBy); | |
} | |
#endregion Increment 2 | |
#region Increment 1 | |
public static ulong Increment(ref ulong obj) | |
{ | |
return Increment(ref obj, 1); | |
} | |
public static long Increment(ref long obj) | |
{ | |
return Increment(ref obj, 1); | |
} | |
public static uint Increment(ref uint obj) | |
{ | |
return Increment(ref obj, 1); | |
} | |
public static int Increment(ref int obj) | |
{ | |
return Increment(ref obj, 1); | |
} | |
public static sbyte Increment(ref sbyte obj) | |
{ | |
return Increment(ref obj, 1); | |
} | |
public static byte Increment(ref byte obj) | |
{ | |
return Increment(ref obj, 1); | |
} | |
public static ushort Increment(ref ushort obj) | |
{ | |
return Increment(ref obj, 1); | |
} | |
public static short Increment(ref short obj) | |
{ | |
return Increment(ref obj, 1); | |
} | |
#endregion Increment 1 | |
#region Read | |
public static object Read(ref object obj) | |
{ | |
return Interlocked.CompareExchange(ref obj, 0, 0); | |
} | |
public static double Read(ref double obj) | |
{ | |
return Interlocked.CompareExchange(ref obj, 0, 0); | |
} | |
public static float Read(ref float obj) | |
{ | |
return Interlocked.CompareExchange(ref obj, 0, 0); | |
} | |
public static IntPtr Read(ref IntPtr obj) | |
{ | |
return Interlocked.CompareExchange(ref obj, IntPtr.Zero, IntPtr.Zero); | |
} | |
public static uint Read(ref uint obj) | |
{ | |
return Interlocked.CompareExchange(ref obj, 0, 0); | |
} | |
public static ulong Read(ref ulong obj) | |
{ | |
return Interlocked.CompareExchange(ref obj, 0, 0); | |
} | |
public static int Read(ref int obj) | |
{ | |
return Interlocked.CompareExchange(ref obj, 0, 0); | |
} | |
public static long Read(ref long obj) | |
{ | |
return Interlocked.CompareExchange(ref obj, 0, 0); | |
} | |
public static byte Read(ref byte obj) | |
{ | |
return Read<byte>(ref obj); | |
} | |
public static sbyte Read(ref sbyte obj) | |
{ | |
return Read<sbyte>(ref obj); | |
} | |
public static ushort Read(ref ushort obj) | |
{ | |
return Read<ushort>(ref obj); | |
} | |
public static short Read(ref short obj) | |
{ | |
return Read<short>(ref obj); | |
} | |
public static bool Read(ref bool obj) | |
{ | |
return Read<bool>(ref obj); | |
} | |
#endregion Read | |
#region Write | |
public static void Write(ref ulong obj, ulong val) | |
{ | |
Interlocked.Exchange(ref obj, val); | |
} | |
public static void Write(ref long obj, long val) | |
{ | |
Interlocked.Exchange(ref obj, val); | |
} | |
public static void Write(ref uint obj, uint val) | |
{ | |
Interlocked.Exchange(ref obj, val); | |
} | |
public static void Write(ref int obj, int val) | |
{ | |
Interlocked.Exchange(ref obj, val); | |
} | |
public static void Write(ref IntPtr obj, IntPtr val) | |
{ | |
Interlocked.Exchange(ref obj, val); | |
} | |
public static void Write(ref double obj, double val) | |
{ | |
Write<double>(ref obj, val); | |
} | |
public static void Write(ref float obj, float val) | |
{ | |
Write<float>(ref obj, val); | |
} | |
public static void Write(ref byte obj, byte val) | |
{ | |
Write<byte>(ref obj, val); | |
} | |
public static void Write(ref sbyte obj, sbyte val) | |
{ | |
Write<sbyte>(ref obj, val); | |
} | |
public static void Write(ref ushort obj, ushort val) | |
{ | |
Write<ushort>(ref obj, val); | |
} | |
public static void Write(ref short obj, short val) | |
{ | |
Write<short>(ref obj, val); | |
} | |
public static void Write(ref bool obj, bool val) | |
{ | |
Write<bool>(ref obj, val); | |
} | |
public static void Write(ref object obj, object val) | |
{ | |
Write<object>(ref obj, val); | |
} | |
#endregion Write | |
#region Generic Methods | |
public static T CompareExchange<T>(ref T obj, Func<T, T> func, T compared) | |
{ | |
if (obj == null) | |
throw new NullReferenceException(nameof(obj)); | |
Thread.MemoryBarrier(); | |
T returnVal = obj; | |
if (returnVal.Equals(compared)) | |
obj = Exchange<T>(ref obj, func); | |
return returnVal; | |
} | |
public static T Read<T>(ref T obj) | |
{ | |
Thread.MemoryBarrier(); | |
T returnVal = obj; | |
return returnVal; | |
} | |
public static T Write<T>(ref T obj, T value) | |
{ | |
Thread.MemoryBarrier(); | |
obj = value; | |
return obj; | |
} | |
#endregion Generic Methods | |
#region Internal IncrementDecrement | |
private static T _Internal_IncrementDecrement<T>(ref T obj, int decision, int val) where T : unmanaged | |
{ | |
if (decision != 1 && decision != -1) | |
throw new ArgumentException("decision must be -1 or 1 to do increment, decrement"); | |
Thread.MemoryBarrier(); | |
if (typeof(T) == typeof(byte)) | |
return (T)(object)(byte)(Interlocked.Add(ref Unsafe.As<T, int>(ref obj), decision * val)); | |
if (typeof(T) == typeof(sbyte)) | |
return (T)(object)(sbyte)(Interlocked.Add(ref Unsafe.As<T, int>(ref obj), decision * val)); | |
if (typeof(T) == typeof(short)) | |
return (T)(object)(short)(Interlocked.Add(ref Unsafe.As<T, int>(ref obj), decision * val)); | |
if (typeof(T) == typeof(ushort)) | |
return (T)(object)(ushort)(Interlocked.Add(ref Unsafe.As<T, int>(ref obj), decision * val)); | |
throw new ArgumentException($"Unsupported type: {typeof(T).Name}"); | |
} | |
private static T _InternalDecrementBy<T>(ref T obj, int decrementBy) where T : unmanaged | |
{ | |
return _Internal_IncrementDecrement(ref obj, -1, decrementBy); | |
} | |
private static T _InternalIncrementBy<T>(ref T obj, int incrementBy) where T : unmanaged | |
{ | |
return _Internal_IncrementDecrement(ref obj, 1, incrementBy); | |
} | |
#endregion Internal IncrementDecrement | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Extendlocked | |
{ | |
using Extendlocked; | |
using System; | |
using BenchmarkDotNet.Running; | |
internal class Program | |
{ | |
private static void Main(string[] args) | |
{ | |
var summary = BenchmarkRunner.Run(typeof(Program).Assembly); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment