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; var queue = new ConcurrentQueue(new[] { 0, 1 }); using var peeked = new Barrier(2); int[] seen = new int[2], removed = new int[2]; void Consume(int index) { if (!queue.TryPeek(out seen[index])) throw new InvalidOperationException(); if (!peeked.SignalAndWait(TimeSpan.FromSeconds(5))) throw new TimeoutException(); if (!queue.TryDequeue(out removed[index])) throw new InvalidOperationException(); } OwnedThreads.Run(() => Consume(0), () => Consume(1)); Console.WriteLine($"same-peek:{seen[0] == 0 && seen[1] == 0}"); Console.WriteLine($"distinct-removals:{removed.Distinct().Count() == 2}"); Console.WriteLine($"remaining:{queue.Count}"); 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); } }