using System.Threading.Tasks;
using System.Runtime.CompilerServices;
public static class Program
public static void Main()
ThreadSafeData<(int, int, int, int, int, int, int, int, int)> data = new();
using CancellationTokenSource cts = new(1000);
Task<int> writer = new Task<int>(() =>
while (!cts.IsCancellationRequested)
int value = random.Next();
data.SetData((value, value, value, value, value, value, value, value, value));
Thread.SpinWait(writerSpinCount);
Task<(int, int)>[] readers = Enumerable.Range(1, readersCount).Select(n => new Task<(int, int)>(() =>
while (!cts.IsCancellationRequested)
if (d.Item1 != d.Item2 || d.Item1 != d.Item3 || d.Item1 != d.Item4 || d.Item1 != d.Item5 || d.Item1 != d.Item6 || d.Item1 != d.Item7 || d.Item1 != d.Item8 || d.Item1 != d.Item9)
if (tornValues == 1) Console.WriteLine($"Reader #{n}, First torn value: {d}");
Thread.SpinWait(readerSpinCount);
return (iterations, tornValues);
Console.WriteLine($"Type: {data.GetType().Name}, Tuple.Length: {((ITuple)data.GetData()).Length:#,0}");
Console.WriteLine($"Writer (1) SpinCount: {writerSpinCount:#,0}");
Console.WriteLine($"Reader ({readers.Length}) SpinCount: {readerSpinCount:#,0}");
ThreadPool.SetMinThreads(readers.Length + 1, 4);
Task allTasks = Task.WhenAll(readers.Cast<Task>().Prepend(writer).ToArray());
long mem0 = GC.GetTotalAllocatedBytes(true);
Array.ForEach(readers, r => r.Start(TaskScheduler.Default));
writer.RunSynchronously(TaskScheduler.Default);
long mem1 = GC.GetTotalAllocatedBytes(true);
Console.WriteLine($"Writer iterations: {writer.Result:#,0}");
Console.WriteLine($"Reader iterations: {String.Join(", ", readers.Select(r => $"{r.Result.Item1:#,0}"))} (Sum: {readers.Select(r => r.Result.Item1).Sum():#,0})");
int sumTornValues = readers.Select(r => r.Result.Item2).Sum();
if (sumTornValues > 0) Console.WriteLine($"Torn values: {String.Join(", ", readers.Select(r => $"{r.Result.Item2:#,0}"))} (Sum: {sumTornValues:#,0})");
Console.WriteLine($"Allocated: {mem1 - mem0:#,0} bytes");
public struct ThreadSafeData<T>
private int lastSetIndex;
public void SetData(T data)
dataArray[setterIndex] = data;
lastSetIndex = setterIndex;
setterIndex = lastSetIndex * - 1 + 1;
return dataArray[lastSetIndex];