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(); bool rejected = false; lock (sync) { lock (sync) { if (!Monitor.IsEntered(sync)) throw new InvalidOperationException(); } OwnedThreads.Run(() => { try { Monitor.Exit(sync); } catch (SynchronizationLockException) { rejected = true; } }); } Console.WriteLine($"wrong-owner:{rejected}"); Console.WriteLine($"after:{Monitor.IsEntered(sync)}"); 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); } }