When is it appropriate to use either the Monitor
class or the lock
keyword for thread safety in C#?
EDIT: It seems from the answers so far that lock
is short hand for a series of calls to the Monitor
class. What exactly is the lock call short-hand for? Or more explicitly,
class LockVsMonitor { private readonly object LockObject = new object(); public void DoThreadSafeSomethingWithLock(Action action) { lock (LockObject) { action.Invoke(); } } public void DoThreadSafeSomethingWithMonitor(Action action) { // What goes here ? } }
Update
Thank you all for your help : I have posted a another question as a follow up to some of the information you all provided. Since you seem to be well versed in this area, I have posted the link: What is wrong with this solution to locking and managing locked exceptions?
Both Monitor and lock provides a mechanism that synchronizes access to objects. lock is the shortcut for Monitor. Enter with try and finally. Lock is a shortcut and it's the option for the basic usage.
A lock typically prevents more than one entity from accessing a shared resource. Each object in the Java language has an associated lock, also referred to as a monitor, which a thread obtains by using a synchronized method or block of code.
The monitor lock only exist inside a single process, while the Mutex -lock is machine wide. So a monitor lock is appropriate for making objects and data-structures thread safe, but not for providing system-wide exclusive access to say a file or device.
Monitor in Java Concurrency is a synchronization mechanism that provides the fundamental requirements of multithreading namely mutual exclusion between various threads and cooperation among threads working at common tasks. Monitors basically 'monitor' the access control of shared resources and objects among threads.
Eric Lippert talks about this in his blog: Locks and exceptions do not mix
The equivalent code differs between C# 4.0 and earlier versions.
In C# 4.0 it is:
bool lockWasTaken = false; var temp = obj; try { Monitor.Enter(temp, ref lockWasTaken); { body } } finally { if (lockWasTaken) Monitor.Exit(temp); }
It relies on Monitor.Enter
atomically setting the flag when the lock is taken.
And earlier it was:
var temp = obj; Monitor.Enter(temp); try { body } finally { Monitor.Exit(temp); }
This relies on no exception being thrown between Monitor.Enter
and the try
. I think in debug code this condition was violated because the compiler inserted a NOP between them and thus made thread abortion between those possible.
lock
is just shortcut for Monitor.Enter
with try
+ finally
and Monitor.Exit
. Use lock statement whenever it is enough - if you need something like TryEnter, you will have to use Monitor.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With