Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I put a return statement inside a lock

Tags:

c#

locking

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.

like image 806
DevinB Avatar asked Aug 31 '09 20:08

DevinB


1 Answers

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.

like image 67
Andrew Hare Avatar answered Sep 23 '22 17:09

Andrew Hare