Can I put a return statement inside a lock

守給你的承諾、 提交于 2019-12-18 14:40:33

问题


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

The title is a little misleading. I know that you can do it, but I'm wondering about the performance implications.

consider these two blocks of code. (no error handling)

This block has the return outside of the lock

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

This block has the return statement within the lock

 public DownloadFile Dequeue()
 {
     lock (QueueModifierLockObject)
     {
         DownloadFile toReturn = queue[0];
         queue.RemoveAt(0);

         return toReturn;
     }
 }

Is there any difference in the code? I understand that the performance differences (if any) would be minimal, but I am specifically wondering if there would be a difference in the order that the lock gets release.


回答1:


The C# compiler will move the return statement outside of the try/finally that is created for the lock statement. Both of your examples are identical in terms of the IL that the compiler will emit for them.

Here is a simple example proving that:

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;
    }
}

The code above gets compiled to the following:

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;
        }
}

As you can see, the compiler has taken the libery of moving the return statement in Foo outside of the try/finally.




回答2:


I believe the IL would be identical... I'd have to test it to be fer sure, but the lock statement generates a try finally in the IL, and the return would trigger the finally (with the release) BEFORE the stack frame closes and returns to the caller anyway, so...




回答3:


Yes, but why not use Dequeue?

Remember lock is simply shorthand for essentially something along the lines of:

        try
        {
            Monitor.Enter(QueueModifierLockObject);

            DownloadFile toReturn = queue.Dequeue();         

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


来源:https://stackoverflow.com/questions/1359184/can-i-put-a-return-statement-inside-a-lock

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!