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解锁 ,形成死锁。

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

  • 相关阅读:
    很实用的jQuery事件
    移动端touchstart,touchmove,touchend
    Django的学习(二)————Templates
    Django的学习(一)————初入django
    Tkinter添加图片
    HierSort(希尔)————Java
    Bubble(冒泡排序)————Java
    类+进程池的方法爬取喜马拉雅
    Ajax的爬取心得
    python中将两个数组压缩成一个数组
  • 原文地址:https://www.cnblogs.com/change-myself/p/11161811.html
Copyright © 2011-2022 走看看