How expensive is the lock statement?
Here is an article that goes into the cost. Short answer is 50ns.
How expensive is lock(...) when the lock isn't contended?
We can test it...
I get:
1000000000; 2164 (no lock)
1000000000; 23258 (lock)
21.094ns per lock
Code:
using System;
using System.Diagnostics;
static class P
{
static void Main()
{
Test(1); // for JIT
Test(1000000);
}
static readonly object syncLock = new object();
static void Test(int count)
{
int j = 0;
var watch = Stopwatch.StartNew();
for(int i = 0 ; i < count ; i++)
{
for (int z = 0; z < 1000; z++)
j++;
}
watch.Stop();
long withoutMillis = watch.ElapsedMilliseconds;
Console.WriteLine("{0}; {1} (no lock)", j, watch.ElapsedMilliseconds);
j = 0;
watch = Stopwatch.StartNew();
for (int i = 0; i < count; i++)
{
for (int z = 0; z < 1000; z++ )
lock (syncLock)
{
j++;
}
}
watch.Stop();
long withMillis = watch.ElapsedMilliseconds;
Console.WriteLine("{0}; {1} (lock)", j, watch.ElapsedMilliseconds);
long deltaNano = (withMillis - withoutMillis) * 1000000;
// nano = 1000 micro = 1000000 milli
double perLockNano = deltaNano/(1000.0 * count);
Console.WriteLine("{0}ns per lock", perLockNano);
}
}
What is the reason for locks are an expensive operation to be uttered so often?
Is it the fact that it causes a LOCK# instruction to be emitted at Assembler level?
No, since it doesn't always do that.
Is it the fact that obtaining a lock requires a kernel call into the OS?
No, since it typically doesn't do that.
In fact, locks are very, very inexpensive. It's contention that's expensive. If you have to choose between a lock and contention, most of the time the lock is a better option.
Locks, when used properly, are a contention avoidance mechanism. They automatically find threads that contend and de-schedule them such that one winds up primarily with threads that do not contend running concurrently.
For example: Say you have four threads that are ready to run, A, B, C, and D. Say A and B contend with each other (say they manipulate the same collection). And say C and D contend with each other, but A doesn't contend with C. If A and B are running at the same time (contending), the locks will cause one of them to not be ready to run, the scheduler will then schedule C (or D), and the two threads will run without further contention. (At least until the next context switch.)
Usually, when people say "locks are expensive", they mean that contention is expensive. Unfortunately, by phrasing it the way they do, they often encourage people to minimize locks but increase contention in the process. That is a losing proposition in the vast majority of cases. (There are a few exceptions.)
What does a lock statement do under the hood?
The lock
statement is translated by C# 3.0 to the following:
var temp = obj;
Monitor.Enter(temp);
try
{
// body
}
finally
{
Monitor.Exit(temp);
}
In C# 4.0 this has changed and it is now generated as follows:
bool lockWasTaken = false;
var temp = obj;
try
{
Monitor.Enter(temp, ref lockWasTaken);
// body
}
finally
{
if (lockWasTaken)
{
Monitor.Exit(temp);
}
}
You can find more info about what Monitor.Enter
does here. To quote MSDN:
Use
Enter
to acquire the Monitor on
the object passed as the parameter. If
another thread has executed anEnter
on the object but has not yet executed
the correspondingExit
, the current
thread will block until the other
thread releases the object. It is
legal for the same thread to invoke
Enter
more than once without it
blocking; however, an equal number of
Exit
calls must be invoked before
other threads waiting on the object
will unblock.
The Monitor.Enter
method will wait infinitely; it will not time out.
Related Topics
Is There Windows System Event on Active Window Changed
Hashset That Preserves Ordering
C# Implementation of Deep/Recursive Object Comparison in .Net 3.5
Explicitly Cast Generic Type Parameters to Any Interface
How to Read the Data in a Wav File to an Array
How Expensive Is the Lock Statement
How to Not Serialize the _Type Property on JSON Objects
How to Ensure an Event Is Only Subscribed to Once
How to Create an Explorer-Like Folder Browser Control
How to Render a Wpf Usercontrol to a Bitmap Without Creating a Window
ASP.NET 2012 Unobtrusive Validation with Jquery
Selecting a Textbox Item in a Listbox Does Not Change the Selected Item of the Listbox