6

Does the c# lock keyword use a 'yielding', 'spin-locking' or hybrid approach to handle contention?

So far my searches on the .net lock statement hasn't turned up an answer. I will post if I do find any more. So far all I could find is When should one use a spinlock ... with a nicely worded accepted answer by Mecki.

But I am looking for some definitive answer or documentation regarding .net/c# if anyone has one.

Community
  • 1
  • 1
Vort3x
  • 1,778
  • 2
  • 20
  • 37

3 Answers3

11

Following code:

lock (_syncRoot)
{
    // Do stuff
}

Is translated by the compiler to:

Monitor.Enter(_syncRoot)
try
{
    // Do stuff
}
finally
{
    Monitor.Exit(_syncRoot);
}

This is the naive (and old) implementation, actually with .NET 4.0 the implementation is more or less this (see Eric's blog for complete reference):

bool locked = false;
try
{
    Monitor.Enter(_syncRoot, ref locked);
}
finally
{
    if (locked)
        Monitor.Exit(_syncRoot);
}

EDITED

That said the question is how Monitor.Enter() works? Well, default Mono implementation uses a semaphore to acquire the lock but Microsoft .NET implementation acts different.

I was reading Concurrent Windows Programming (by Joe Duffy) when a paragraph did catch my attention, my first answer said "no, it doesn't use spinning because performance may not be good in general cases". Correct answer is "yes, .NET Monitor uses spinning". Both .NET Monitor and Windows Critical Sections perform a short spinning before falling back to a true wait on a kernel object. This algorithm is called "two-phase locking protocol" and it's appropriate because context switches and kernel transitions are very expansive, on a multiprocessor machine spinning can avoid both of them.

Moreover do not forget these are implementation details and can change in any release (or algorithm can be different for different hardwares because of JIT compiler).

Adriano Repetti
  • 65,416
  • 20
  • 137
  • 208
1
lock (obj)
{
}

was just syntactic sugar for Monitor.Enter in a try...finally.

Monitor.Enter(obj);
try
{
}
finally
{
    Monitor.Exit(obj);
}

It is now something a little better (Thanks to Mark and Adriano for keeping me current).

bool locked = false;  
try  
{  
    Monitor.Enter(_syncRoot, ref locked);  
}  
finally  
{  
    if (locked)  
        Monitor.Exit(_syncRoot);  
} 
DaveShaw
  • 52,123
  • 16
  • 112
  • 141
0

This is Microsoft documentation saying lock() wraps Monitor.Enter/Exit

"use the C# lock statement, which wraps the Enter and Exit methods in a try…finally block."

from http://msdn.microsoft.com/en-us/library/de0542zz.aspx

If you want a spinlock type you can use ReaderWriterLockSlim()

http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim.aspx

IvoTops
  • 3,463
  • 17
  • 18
  • why downvote this without comment? I point to documentation requested and suggest an alternative which uses the spinlock that is mentioned. – IvoTops Jul 06 '12 at 13:24