using System; using System.Linq; using System.Collections.Generic; using System.Collections.Concurrent; using System.Reflection; using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; int split = 0; using var barrier = new Barrier(2); void SplitIncrement() { int before = Volatile.Read(ref split); if (!barrier.SignalAndWait(TimeSpan.FromSeconds(5))) throw new TimeoutException(); Volatile.Write(ref split, before + 1); } OwnedThreads.Run(SplitIncrement, SplitIncrement); int atomic = 0; OwnedThreads.Run(Enumerable.Range(0, 4).Select(_ => (Action)(() => { for (int i = 0; i < 100; i++) Interlocked.Increment(ref atomic); })).ToArray()); Console.WriteLine($"separate-read-write:{split}"); Console.WriteLine($"atomic:{atomic}"); public static class OwnedThreads { public static void Run(params Action[] actions) { var errors = new ConcurrentQueue(); var threads = actions.Select(action => new Thread(() => { try { action(); } catch (Exception error) { errors.Enqueue(error); } }) { IsBackground = true }).ToArray(); foreach (var thread in threads) thread.Start(); foreach (var thread in threads) if (!thread.Join(TimeSpan.FromSeconds(8))) throw new TimeoutException("Owned worker did not finish"); if (!errors.IsEmpty) throw new AggregateException(errors); } }