Monitor vs lock
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.
In Java, what is the difference between a monitor and a lock
From the official documentation of Locks and Synchronization:
- Synchronization is built around an internal entity known as the intrinsic lock or monitor lock. (The API specification often refers to this entity simply as a "monitor.")
- Every object has an intrinsic lock associated with it. By convention, a thread has to acquire the object's monitor lock
before accessing them, and then release the monitor lock when it's
done with them. A thread is said to own the lock between the time it
has acquired the lock and released the lock. As long as a thread owns
a monitor lock, no other thread can acquire the same lock. The other
thread will block when it attempts to acquire the lock.- When a thread releases the lock, a happens-before relationship is established between that action and any subsequent acquisition of the
same lock.
So a monitor and a lock can not be compared for differences, rather they are complementary to each other. Every object in Java is associated with a monitor which a thread can lock or unlock.
Difference Between Monitor & Lock?
For example in C# .NET a lock statement is equivalent to:
Monitor.Enter(object);
try
{
// Your code here...
}
finally
{
Monitor.Exit(object);
}
However, keep in mind that Monitor can also Wait()
and Pulse()
, which are often useful in complex multithreading situations.
Edit:
In later versions of the .NET framework, this was changed to:
bool lockTaken = false;
try
{
Monitor.Enter(object, ref lockTaken);
// Your code here...
}
finally
{
if (lockTaken)
{
Monitor.Exit(object);
}
}
Monitor vs Mutex
Since you haven't specified which OS or language/library you are talking about, let me answer in a generic way.
Conceptually they are the same. But usually they are implemented slightly differently
Monitor
Usually, the implementation of monitors is faster/light-weight, since it is designed for multi-threaded synchronization within the same process. Also, usually, it is provided by a framework/library itself (as opposed to requesting the OS).
Mutex
Usually, mutexes are provided by the OS kernel and libraries/frameworks simply provide an interface to invoke it. This makes them heavy-weight/slower, but they work across threads on different processes. OS might also provide features to access the mutex by name for easy sharing between instances of separate executables (as opposed to using a handle that can be used by fork
only).
Does Monitor.TryEnter and lock() work together?
lock will block until the resource is available
TryEnter will not do anything if it is already locked.
Depending on your needs you have to use one or the other.
In your case f2()
will always do what ever it does no matter how long it takes. f1()
will return immediately if there is lock contention
Using lock, Monitor Pulse and Wait to synchronize threads
Here is a relatively simple Wait
/PulseAll
example:
object locker = new();
int i = 0;
bool finished = false;
Thread[] threads = Enumerable.Range(0, 3).Select(remainder => new Thread(() =>
{
lock (locker)
{
try
{
do
{
while (!finished && i % 3 != remainder) Monitor.Wait(locker);
if (finished) break;
Console.WriteLine($"Worker #{remainder} produced {i}");
Monitor.PulseAll(locker);
} while (++i < 20);
}
finally { finished = true; Monitor.PulseAll(locker); }
}
})).ToArray();
Array.ForEach(threads, t => t.Start());
Array.ForEach(threads, t => t.Join());
Three worker threads are created, identified by the remainder
argument, that takes the values 0, 1, and 2. Each worker is responsible for producing numbers whose module 3 equals the remainder.
The int i
is the loop variable, and the bool finished
is a flag that becomes true
when any worker is finished. This flag ensures that in case of an error in any worker, the other workers will not deadlock.
Each worker enters a critical section that encloses a do-while
loop, which is the number-producing and incrementing loop. Before emitting a number it has to wait for its turn. Its turn comes when the i % 3 == remainder
. Otherwise it Wait
s. When its turn comes, it emits the number, it increments the i
, it Pulse
s all waiting workers, and continues with the next iteration. When the loop ends, it Pulse
s one last time before releasing the lock.
The PulseAll
has been chosen instead of the Pulse
, because we don't know whether the next worker in the waiting queue is the correct one for the current i
, so we just wake them all.
Output:
Worker #0 produced 0
Worker #1 produced 1
Worker #2 produced 2
Worker #0 produced 3
Worker #1 produced 4
Worker #2 produced 5
Worker #0 produced 6
Worker #1 produced 7
Worker #2 produced 8
Worker #0 produced 9
Worker #1 produced 10
Worker #2 produced 11
Worker #0 produced 12
Worker #1 produced 13
Worker #2 produced 14
Worker #0 produced 15
Worker #1 produced 16
Worker #2 produced 17
Worker #0 produced 18
Worker #1 produced 19
Try it on fiddle.
Note: the example in the 1st revision of this answer was problematic, because it was creating an initial busy-wait phase until all workers were ready.
Related Topics
C# How to Loop While Mouse Button Is Held Down
How to Make a Background Worker Thread Set to Single Thread Apartment
Static Binding Doesn't Update When Resource Changes
Owin Security - How to Implement Oauth2 Refresh Tokens
Send Http Post Message in ASP.NET Core Using Httpclient Postasjsonasync
Does Mstest Have an Equivalent to Nunit's Testcase
Number of Occurrences of a Character in a String
Minimizing All Open Windows in C#
Autonumber with Entity Framework
Difference Between Delegate.Invoke and Delegate()
How to "Zip" or "Rotate" a Variable Number of Lists
Insert into C# with SQLcommand
How to Crop a Polygonal Area from an Image in a Winform Picturebox
Assign Format of Datetime with Data Annotations
How to Get the Data Type of a Variable in C#