// Exercise 1: fix the races and avoid the deadlock (medium) // // STEP 1: Counter.Increment() is called from many threads at once. Make it atomic with Interlocked. // STEP 2: Bank.Transfer(from, to, amount) moves money between two accounts. Each Account has its own lock // object. Lock BOTH accounts, always in the same order (lower Id first) so two opposite transfers // can't deadlock, and only transfer if `from` has enough balance (return true/false). // // The self-check runs thousands of concurrent operations; a non-atomic or deadlocking version fails or times out. // // Run with: dotnet run (inside a console project). using System; using System.Threading; using System.Threading.Tasks; class Counter { int _value; public int Value => _value; public void Increment() { _value++; } // TODO: make atomic } class Account { public int Id; public decimal Balance; public readonly object Gate = new object(); } static class Bank { public static bool Transfer(Account from, Account to, decimal amount) { // TODO: lock both accounts in a consistent order if (from.Balance < amount) return false; from.Balance -= amount; to.Balance += amount; return true; } } class Program { static void Main() { int pass = 0, total = 0; void Check(string name, bool ok) { total++; if (ok) pass++; Console.WriteLine($"{(ok ? "PASS" : "FAIL")}: {name}"); } var c = new Counter(); Parallel.For(0, 200_000, _ => c.Increment()); Check($"atomic counter ({c.Value})", c.Value == 200_000); var a = new Account { Id = 1, Balance = 1000m }; var b = new Account { Id = 2, Balance = 1000m }; var task = Task.Run(() => Parallel.For(0, 20_000, i => { if (i % 2 == 0) Bank.Transfer(a, b, 1m); else Bank.Transfer(b, a, 1m); })); bool finished = task.Wait(TimeSpan.FromSeconds(10)); Check("opposite transfers don't deadlock", finished); Check($"money is conserved ({a.Balance + b.Balance})", finished && a.Balance + b.Balance == 2000m); Check("insufficient funds rejected", !Bank.Transfer(new Account { Id = 3, Balance = 5m }, a, 10m)); Console.WriteLine($"--- {pass}/{total} checks passed ---"); } }