zoukankan      html  css  js  c++  java
  • 线程同步技术

    在上一讲介绍了使用lock来实现线程之间的同步。实际上,这个lock是C#的一个障眼法,在C#编译器编译lock语句时,将其编译成了调用Monitor类。先看看下面的C#源代码:

    public static void MyLock()
    {
        lock (typeof(Program))
        {
        }
    }


        上面的代码通过lock语句使MyLock同步,这个方法被编译成IL后,代码如图1所示。



                                                             图1

        从上图被标注的区域可以看到,一条lock语句被编译成了调用Monitor的Enter和Exit方法。Monitor在System.Threading命名空间中。lock的功能就相当于直接调用Monitor的Entry方法,所不同的是,lock方法在结束后,会自动解除锁定,当然,在IL中是调用了Monitor的Exit方法,但在C#程序中,看起来是自动解锁的,这类似于C#中的using语句,可以自动释放数据库等的资源。但如果直接在C#源程序中使用Monitor类,就必须调用Exit方法来显式地解除锁定。如下面的代码所示:

    Monitor.Entry(lockObj);
    try
    {
        // lockObj的同布区
    }
    catch(Exception e)
    {
        // 异常处理代码
    }
    finally
    {
        Monitor.Exit(lockObj);  // 解除锁定
    }


     

        Exit方法最后在finally里调用,这样无论在方法在发生异常、返回还是正常执行,都会执行到finally,并调用Exit方法解除锁定。

        Monitor类不仅可以完全取代lock语句(如果只使用lock语句本身的功能,最好还是直接用lock语句吧),还可以使用TryEntry方法设置一个锁定超时,单位是毫秒。如下面的代码所示:

    if(Monitor.TryEntry(lockObj, 1000))
    {
        try
        {
        }
        finally
        {
            Monitor.Exit(lockObj);
        }
    }
    else
    {
        // 超时后的处理代码
    }

        上面的代码设置了锁定超时时间为1秒,也就是说,在1秒中后,lockObj还未被解锁,TryEntry方法就会返回false,如果在1秒之内,lockObj被解锁,TryEntry返回true。我们可以使用这种方法来避免死锁,如下面的代码所示:

        class Program
        {
            private static Object objA = new Object();
            private static Object objB = new Object();
            public static void LockA()
            {
                if (Monitor.TryEnter(objA, 1000))
                {
                    Thread.Sleep(1000);
                    if (Monitor.TryEnter(objB, 2000))
                    {
                        Monitor.Exit(objB);
                    }
                    else
                    {

                        Console.WriteLine("LockB timeout");
                    }
                    Monitor.Exit(objA);
                }
                Console.WriteLine("LockA");
            }
            public static void LockB()
            {
                if (Monitor.TryEnter(objB, 2000))
                {
                    Thread.Sleep(2000);
                    if (Monitor.TryEnter(objA, 1000))
                    {
                        Monitor.Exit(objA);
                    }
                    else
                    {
                        Console.WriteLine("LockA timeout");
                    }
                    Monitor.Exit(objB);
                }
                Console.WriteLine("LockB");
            }
            public static void Main()
            {
                Thread threadA = new Thread(LockA);
                Thread threadB = new Thread(LockB);
                threadA.Start();
                threadB.Start();
                Thread.Sleep(4000);         
                Console.WriteLine("线程结束");
            }
        }

        上面的代码是在上一讲举的死锁的例子,但在这一讲将lock语句改成了TryEntry方法,而且设置了锁定超时间,由于在等待一定时间后,不管被锁定的对象是否被解锁,TryEntry方法都会返回,因此,上面的代码是不会死锁的。运行上面的代码的结果如图2所示。



                                                  图2

        如果TryEntry方法的超时时间为System.Threading.Timeout.Infinite,TryEntry方法就相当于Entry方法,如果超时时间为0,不管是否解锁,TryEntry方法都会立即返回。

  • 相关阅读:
    CSU 1333 Funny Car Racing
    FZU 2195 检查站点
    FZU 2193 So Hard
    ZOJ 1655 FZU 1125 Transport Goods
    zoj 2750 Idiomatic Phrases Game
    hdu 1874 畅通工程续
    hdu 2489 Minimal Ratio Tree
    hdu 3398 String
    洛谷 P2158 [SDOI2008]仪仗队 解题报告
    POJ 1958 Strange Towers of Hanoi 解题报告
  • 原文地址:https://www.cnblogs.com/yanyao/p/5376479.html
Copyright © 2011-2022 走看看