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 sync = new object(); var queue = new Queue(); using var waiting = new ManualResetEventSlim(); int value = -1; OwnedThreads.Run( () => { lock (sync) { waiting.Set(); while (queue.Count == 0) if (!Monitor.Wait(sync, TimeSpan.FromSeconds(5)) && queue.Count == 0) throw new TimeoutException(); value = queue.Dequeue(); } }, () => { if (!waiting.Wait(TimeSpan.FromSeconds(5))) throw new TimeoutException(); lock (sync) { queue.Enqueue(7); Monitor.PulseAll(sync); } }); Console.WriteLine($"value:{value}"); 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); } }