Consider the follow code snippet:ide
1 class Program 2 { 3 static int _hours = 0; 4 5 static void Main(string[] args) 6 { 7 var tasks = new Task[2]; 8 for (int i = 0; i < tasks.Length; i++) 9 { 10 tasks[i] = new Task(Work); 11 tasks[i].Start(); 12 } 13 14 for (int i = 0; i < tasks.Length; i++) 15 { 16 tasks[i].Wait(); 17 } 18 19 Console.WriteLine(_hours); 20 } 21 22 static void Work() 23 { 24 for (int i = 0; i < 8; i++) 25 { 26 Thread.Sleep(10); 27 _hours += 1; 28 Console.WriteLine("task:{0},nth:{1},hours:{2}", Thread.CurrentThread.ManagedThreadId, i, _hours); 29 } 30 } 31 }
The run resut of above code is:this
task:4,nth:0,hours:1 task:3,nth:0,hours:2 task:4,nth:1,hours:3 task:3,nth:1,hours:4 task:4,nth:2,hours:6 task:3,nth:2,hours:6 task:4,nth:3,hours:7 task:3,nth:3,hours:7 task:4,nth:4,hours:9 task:3,nth:4,hours:9 task:3,nth:5,hours:10 task:4,nth:5,hours:11 task:3,nth:6,hours:13 task:4,nth:6,hours:13 task:3,nth:7,hours:15 task:4,nth:7,hours:15 15 Press any key to continue . . .
Please observe the values of hours, and it's final value is 15 instead of 16.spa
From bussiness perspective, each task works 8 hours, so two tasks should work 16 hours. But the result is 15, why?3d
The problem is caused by Thread Synchronization.code
We can resolve it using Synchronization technique.blog
1. Using Lockip
1 class Program 2 { 3 static int _hours = 0; 4 static object _synRoot = new object(); 5 6 static void Main(string[] args) 7 { 8 var tasks = new Task[2]; 9 for (int i = 0; i < tasks.Length; i++) 10 { 11 tasks[i] = new Task(Work); 12 tasks[i].Start(); 13 } 14 15 for (int i = 0; i < tasks.Length; i++) 16 { 17 tasks[i].Wait(); 18 } 19 20 Console.WriteLine(_hours); 21 } 22 23 static void Work() 24 { 25 for (int i = 0; i < 8; i++) 26 { 27 Thread.Sleep(10); 28 lock (_synRoot) 29 { 30 _hours += 1; 31 } 32 Console.WriteLine("task:{0},nth:{1},hours:{2}", Thread.CurrentThread.ManagedThreadId, i, _hours); 33 } 34 } 35 }
The run resut of above code is:rem
task:3,nth:0,hours:2 task:4,nth:0,hours:2 task:4,nth:1,hours:3 task:3,nth:1,hours:4 task:3,nth:2,hours:5 task:4,nth:2,hours:6 task:3,nth:3,hours:7 task:4,nth:3,hours:8 task:4,nth:4,hours:9 task:3,nth:4,hours:10 task:4,nth:5,hours:11 task:3,nth:5,hours:12 task:3,nth:6,hours:14 task:4,nth:6,hours:14 task:4,nth:7,hours:15 task:3,nth:7,hours:16 16 Press any key to continue . . .
As the result shown, we get the correct value 16 now.get
2. Using Interlockedstring
class Program { static int _hours = 0; static object _synRoot = new object(); static void Main(string[] args) { var tasks = new Task[2]; for (int i = 0; i < tasks.Length; i++) { tasks[i] = new Task(Work); tasks[i].Start(); } for (int i = 0; i < tasks.Length; i++) { tasks[i].Wait(); } Console.WriteLine(_hours); } static void Work() { for (int i = 0; i < 8; i++) { Thread.Sleep(10); Interlocked.Increment(ref _hours); //_hours++; Using this statement may result in an unexpected value. Console.WriteLine("task:{0},nth:{1},hours:{2}", Thread.CurrentThread.ManagedThreadId, i, _hours); } } }
The run resut of above code is:
task:5,nth:0,hours:1 task:3,nth:0,hours:2 task:3,nth:1,hours:4 task:5,nth:1,hours:4 task:5,nth:2,hours:5 task:3,nth:2,hours:6 task:5,nth:3,hours:7 task:3,nth:3,hours:8 task:3,nth:4,hours:9 task:5,nth:4,hours:10 task:5,nth:5,hours:12 task:3,nth:5,hours:12 task:5,nth:6,hours:13 task:3,nth:6,hours:14 task:3,nth:7,hours:15 task:5,nth:7,hours:16 16 Press any key to continue . . .