Reputation: 8316
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.
Upvotes: 15
Views: 8866
Reputation: 146557
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...
Upvotes: 2
Reputation: 351586
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
.
Upvotes: 25
Reputation: 933
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);
}
Upvotes: 0