zoukankan      html  css  js  c++  java
  • C# 多线程中的常见问题

    1. 资源竞争

    当多个同时执行的线程需要同时对全局变量进行写读操作时,容易出现资源竞争的问题,导致运行结果出现多种情况。以下面的例子进行说明:

            private static CancellationTokenSource cs = new CancellationTokenSource();
            private static int num = 5;
            private static object obj = new object();
    
            static void Main(string[] args)
            {
                Console.WriteLine("Main Start....");
                Task t1 = Task.Factory.StartNew(Test);
                Task t2 = Task.Factory.StartNew(Test);
                Task.WaitAll(new Task[] { t1, t2 });
                cs.Dispose();
                Console.WriteLine("Main end....");
                Console.ReadLine();
            }
    
            static void Test()
            {
                while (!cs.IsCancellationRequested)    //是否调用Cancel
                {
                    Console.WriteLine("TaskId {0} Excute other code....num is {1}",Task.CurrentId,num);
                    if(num == 5){
                        Thread.Sleep(50);        //为了方便观察,添加延时
                        num++;                    
                        Console.WriteLine("TaskId {0} and Num is {1}", Task.CurrentId, num);
                        if (!cs.IsCancellationRequested)
                        {
                            cs.Cancel();       //取消操作
                        }
                    }
                }
            }

     大多数情况,运行结果如下:

    Main Start....
    TaskId 1 Excute other code....num is 5
    TaskId 2 Excute other code....num is 5
    TaskId 2 and Num is 6
    TaskId 1 and Num is 7
    Main end....

    任务1 首先运行至Thread.Sleep(50),等待50ms,cpu开始调度任务2运行至Thread.Sleep(50)。 接着任务1 运行num++, 并往控制台输出结果num=6,然后任务2运行num++, 并往控制台输出num=7。但有时也会出现下面这种结果:

    Main Start....
    TaskId 1 Excute other code....num is 5
    TaskId 2 Excute other code....num is 5
    TaskId 2 and Num is 7
    TaskId 1 and Num is 7
    Main end....

    任务1 首先运行至Thread.Sleep(50),等待50ms,cpu开始调度任务2运行至Thread.Sleep(50)。接着任务1 运行num++,cpu马上开始调度任务2运行num++,并往控制台输出num=7,最后调度任务1往控制台输出num=7。

     解决方式:只需加上线程锁lock, 便只会出现第一种运行结果,如下:

            static void Test()
            {
                while (!cs.IsCancellationRequested)    //是否调用Cancel
                {
                    Console.WriteLine("TaskId {0} Excute other code....num is {1}",Task.CurrentId,num);
                    if(num == 5){
                        Thread.Sleep(50);        //为了方便观察,添加延时
                        lock (obj)               //只有一个线程可以操作
                        {
                            num++;                    
                            Console.WriteLine("TaskId {0} and Num is {1}", Task.CurrentId, num);
                        }
                        if (!cs.IsCancellationRequested)
                        {
                            cs.Cancel();       //取消操作
                        }
                    }
                }
            }

     2.线程死锁

    至少有2个线程被挂起,等待对方解锁,线程将无限等待下去。

            private static int num = 5;
            private static object obj1 = new object();
            private static object obj2 = new object();
    
            static void Main(string[] args)
            {
                Console.WriteLine("Main Start....");
                Parallel.Invoke(LockTest1, LockTest2);
                Console.WriteLine("Main end....");
                Console.ReadLine();
            }
    
            static void LockTest1()
            {
                lock(obj1){
                    lock(obj2){
                        Console.WriteLine("LockTest1 is running");
                    }
                }
            }
    
            static void LockTest2()
            {
                lock (obj2)
                {
                    lock (obj1)
                    {
                        Console.WriteLine("LockTest2 is running");
                    }
                }
            }

    运行结果:

    Main Start....
    LockTest1 is running
    LockTest2 is running
    Main end....

    看似正常,但这段程序在极少数的情况下,会出现死锁。例如CPU先运行LockTest1()中lock(obj1), 马上又运行LockTest2()中lock(obj2),这时LockTest1()会等待obj2 解锁,而LockTest2()会等待obj1解锁 ,形成死锁。

    解决方式:在设计程序时,考虑好锁定的顺序,或者定义锁定超时。

  • 相关阅读:
    POJ 2018 二分
    873. Length of Longest Fibonacci Subsequence
    847. Shortest Path Visiting All Nodes
    838. Push Dominoes
    813. Largest Sum of Averages
    801. Minimum Swaps To Make Sequences Increasing
    790. Domino and Tromino Tiling
    764. Largest Plus Sign
    Weekly Contest 128
    746. Min Cost Climbing Stairs
  • 原文地址:https://www.cnblogs.com/change-myself/p/11161811.html
Copyright © 2011-2022 走看看