• c# Thread Synchronization


    Introduce a question

    Consider the follow code snippet:

     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     }
    View Code Detail

    The run resut of above code is:

    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 . . .
    View Code

    Please observe the values of hours, and it's final value is 15 instead of 16.

    From bussiness perspective, each task works 8 hours, so two tasks should work 16 hours. But the result is 15, why?

    Solve the question

      The problem is caused by Thread Synchronization.

      We can resolve it using Synchronization technique.

      1. Using Lock

     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     }
    View Code

    The run resut of above code is:

    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 . . .
    View Code

      As the result shown, we get the correct value 16 now.

    2. Using Interlocked

    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);
                }
            }
        }
    View Code

    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 . . .
    View Code
  • 相关阅读:
    plsql excel导入报错:未发现数据源名称并且未指定默认驱动程序
    exception java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
    Android DiskLruCache 源代码解析 硬盘缓存的绝佳方案
    uestc 360(区间合并)
    UI_UITabBarController
    【C++ Primer】用于大型程序的工具
    Java 从基础到进阶学习之路---类编写以及文档凝视.
    Android 项目的代码混淆,Android proguard 使用说明
    android:Activity四种启动模式简单介绍
    已有数据库(单机)部署Database Vault
  • 原文地址:https://www.cnblogs.com/cnbwang/p/3651706.html
Copyright © 2020-2023  润新知