我可以在锁内放一个return语句

时间:2009-08-31 20:09:45

标签: c# locking

Dupe: return statement in a lock procedure: inside or outside

标题有点误导。我知道你可以做到,但我想知道性能影响。

考虑这两个代码块。 (没有错误处理)

此块在锁定

之外有return
 public DownloadFile Dequeue()
 {
     DownloadFile toReturn = null;
     lock (QueueModifierLockObject)
     {
         toReturn = queue[0];
         queue.RemoveAt(0);
     }
     return toReturn;
 }

此块在锁

中包含return语句
 public DownloadFile Dequeue()
 {
     lock (QueueModifierLockObject)
     {
         DownloadFile toReturn = queue[0];
         queue.RemoveAt(0);

         return toReturn;
     }
 }

代码有什么不同吗?我理解性能差异(如果有的话)会很小,但我特别想知道lock释放的顺序是否存在差异。

3 个答案:

答案 0 :(得分:24)

C#编译器会将return语句移到为try/finally语句创建的lock之外。您的两个示例在编译器将为其发出的IL方面是相同的。

这是一个证明:

的简单示例
class Example
{
    static Object obj = new Object();

    static int Foo()
    {
        lock (obj)
        {
            Console.WriteLine("Foo");
            return 1;
        }
    }

    static int Bar()
    {
        lock (obj)
        {
            Console.WriteLine("Bar");
        }
        return 2;
    }
}

上面的代码被编译为以下代码:

internal class Example
{
        private static object obj;

        static Example()
        {
                obj = new object();
                return;
        }

        public Example()
        {
                base..ctor();
                return;
        }

        private static int Bar()
        {
                int CS$1$0000;
                object CS$2$0001;
                Monitor.Enter(CS$2$0001 = obj);
        Label_000E:
                try
                {
                        Console.WriteLine("Bar");
                        goto Label_0025;
                }
                finally
                {
                Label_001D:
                        Monitor.Exit(CS$2$0001);
                }
        Label_0025:
                CS$1$0000 = 2;
        Label_002A:
                return CS$1$0000;
        }

        private static int Foo()
        {
                int CS$1$0000;
                object CS$2$0001;
                Monitor.Enter(CS$2$0001 = obj);
        Label_000E:
                try
                {
                        Console.WriteLine("Foo");
                        CS$1$0000 = 1;
                        goto Label_0026;
                }
                finally
                {
                Label_001E:
                        Monitor.Exit(CS$2$0001);
                }
        Label_0026:
                return CS$1$0000;
        }
}

正如您所看到的,编译器采用了在Foo之外的try/finally中移动return语句的库。

答案 1 :(得分:2)

我相信IL会是相同的...我必须测试它才能确定,但​​是lock语句最终会在IL中生成一次尝试,并且返回将触发finally(发布时)BEFORE堆栈框架关闭并返回到调用者,所以......

答案 2 :(得分:0)

是的,但为什么不使用Dequeue?

记住锁只是简单的简写,基本上是:

        try
        {
            Monitor.Enter(QueueModifierLockObject);

            DownloadFile toReturn = queue.Dequeue();         

            return toReturn;
        }
        finally
        {
            Monitor.Exit(QueueModifierLockObject);
        }