Lock Keyword in C#

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 an Enter
on the object but has not yet executed
the corresponding Exit, 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.

C# lock keyword: Why is an object necessary for the syntax?

Because you don't just lock - you lock something (you lock a lock).

The point of locking is to disallow two threads from directly competing for the same resource. Therefore, you hide that resource behind an arbitrary object. That arbitrary object acts as a lock. When one thread enters a critical section, it locks the lock and the others can't get in. When the thread finishes its work in the critical section, it unlocks and leaves the keys out for whichever thread happens to come next.

If a program has one resource that's candidate for competing accesses, it's possible that it will have other such resources as well! But often these resources are independent from each other - in other words, it may make sense for one thread to be able to lock one particular resource and another thread in the meantime to be able to lock another resource, without those two interfering.

A resource may also need to be accessed from two critical sections. Those two will need to have the same lock. If each had their own, they wouldn't be effective in keeping the resource uncontested.

Obviously, then, we don't just lock - we lock each particular resource's own lock. But the compiler can't autogenerate that arbitrary lock object silently, because it doesn't know which resources should be locked using the same lock and which ones should have their own lock. That's why you have to explicitly state which lock protects which block (or blocks) of code.

Note that the correct usage of an object as a lock requires that the object is persistent (at least as persistent as the corresponding resource). In other words, you can't create it in a local scope, store it in a local variable and throw it away when the scope exits, because this means you're not actually locking anything. If you have one persistent object acting as a lock for a given resource, only one thread can enter that section. If you create a new lock object every time someone attempts to get in, then anyone can enter at all times.

lock keyword in C#

When should the lock be used?

A lock should be used to protect shared resources in multithreaded code. Not for anything else.

But is it necessary when the application does not spin off any other threads?

Absolutely not. It's just a time waster. However do be sure that you're not implicitly using system threads. For example if you use asynchronous I/O you may receive callbacks from a random thread, not your original thread.

Is there performance issues with using lock?

Yes. They're not very big in a single-threaded application, but why make calls you don't need?

...if that is a good design pattern to follow in the future[?]

Locking everything willy-nilly is a terrible design pattern. If your code is cluttered with random locking and then you do decide to use a background thread for some work, you're likely to run into deadlocks. Sharing a resource between multiple threads requires careful design, and the more you can isolate the tricky part, the better.

c# why put object in the lock statement

I've made a very simple class to illustrate what the object in the lock is there for.

public class Account
{
private decimal _balance = 0m;
private object _transactionLock = new object();
private object _saveLock = new object();

public void Deposit(decimal amount)
{
lock (_transactionLock)
{
_balance += amount;
}
}

public void Withdraw(decimal amount)
{
lock (_transactionLock)
{
_balance -= amount;
}
}

public void Save()
{
lock (_saveLock)
{
File.WriteAllText(@"C:\Balance.txt", _balance.ToString());
}
}
}

You'll notice that I have three locks, but only two variables.

The lines lock (_transactionLock) mutually lock the regions of code to only allow the current thread to enter - and this could mean that the current thread can re-enter the locked region. Other threads are blocked no matter which of the lock (_transactionLock) they hit if a thread already has the lock.

The second lock, lock (_saveLock), is there to show you that the object in the lock statement is there to identify the lock. So, if a thread were in one of the lock (_transactionLock) statements then there is nothing stopping a thread to enter the lock (_saveLock) block (unless another thread were already there).

Confusion about the lock statement in C#

The question is confusingly worded and the answers so far are not particularly clear either. Let me rephrase the question into several questions:

(1) Does the lock statement ensure that no more than one thread is in the body of the lock statement at any one time?

No. For example:

static readonly object lock1 = new object();
static readonly object lock2 = new object();
static int counter = 0;
static object M()
{
int c = Interlocked.Increment(ref counter);
return c % 2 == 0 ? lock1 : lock2;
}

...
lock(M()) { Critical(); }

It is possible for two threads to both be in the body of the lock statement at the same time, because the lock statement locks on two different objects. Thread Alpha can call M() and get lock1, and then thread Beta can call M() and get lock2.

(2) Assuming that my lock statement always locks on the same object, does a lock statement ensure that no more than one "active" thread is in the body of the lock at any one time?

Yes. If you have:

static readonly object lock1 = new object();
...
lock(lock1) { Critical(); }

then thread Alpha can take the lock, and thread Beta will block until the lock is available before entering the lock body.

(3) Assuming that I have two lock statements, and both lock statements lock on the same object every time, does a lock statement ensure that no more than one "active" thread is in the body of either lock at any one time?

Yes. If you have:

static readonly object lock1 = new object();
...
static void X()
{
lock(lock1) { CriticalX(); }
}
static void Y()
{
lock(lock1) { CriticalY(); }
}

then if thread Alpha is in X and takes the lock, and thread Beta is in Y, then thread Beta will block until the lock is available before entering the lock body.

(4) Why are you putting "active" in "scare quotes"?

To call attention to the fact that it is possible for a waiting thread to be in the lock body. You can use the Monitor.Wait method to "pause" a thread that is in a lock body, and allow a blocked thread to become active and enter that lock body (or a different lock body that locks the same object). The waiting thread will stay in its "waiting" state until pulsed. At some time after it is pulsed, it rejoins the "ready" queue and blocks until there is no "active" thread in the lock. It then resumes at the point where it left off.

What type of locking mechanism does lock statement use

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).

C# Lock Statement

Monitor (which is used by the lock statement under the covers) is reentrant, so it's technically ok for the same thread to lock on an object multiple times. The lock will be released when the outer lock scope completes. However, reentrant locks are difficult to reason about and should be avoided unless you have no other option.

Deadlocks do not occur due to reentrant locks. They occur when you take out locks on multiple objects while some other thread locks the same objects in a different order.



Related Topics



Leave a reply



Submit