Lock and monitor

  • Thread starter Fernando Rodríguez
  • Start date
F

Fernando Rodríguez

Hi,

I've been reading the multithreading tutorial at
http://www.yoda.arachsys.com/csharp/threads/locking.shtml (thanks Jon :) and
there's one thing I don't understand.

Why do have to pass a parameter to lock, Monitor.Enter() and Monitor.Exit()?
Why is it necessary to create a new readonly variable for this purpose? (see
below, counterLock)

-----------------------------------------------------------------------------------------
Thread thread = new Thread( new ThreadStart( ThreadJob ) );
thread.Start();

for( int i=0; i < 5; ++i )
{
lock (counterLock)
{
int tmp = count;
Console.WriteLine("Read count={0}", tmp);
Thread.Sleep(50);
tmp++;
Console.WriteLine("Incremented tmp to {0}", tmp);
Thread.Sleep(20);
count = tmp;
Console.WriteLine("Written count={0}", tmp);
}
Thread.Sleep(30);
}
 
D

Daniel O'Connell [C# MVP]

Fernando Rodriguez said:
Hi,

I've been reading the multithreading tutorial at
http://www.yoda.arachsys.com/csharp/threads/locking.shtml (thanks Jon :)
and
there's one thing I don't understand.

Why do have to pass a parameter to lock, Monitor.Enter() and
Monitor.Exit()?
Passing a parameter to these methods allows the value of that parameter to
be used as a marker for the section of code you are locking. lock (obj)
locks on the instance refered to by obj, and thus every lock on that
instance will see the lock and react to it. For example, another lock(obj)
statement will be blocked until the section of code using the obj lock is
released. By locking on a specific object you can coordinate access to a
resource across the entire appdomain, the object instance is just a convient
way of providing unique identification to a given section.
Why is it necessary to create a new readonly variable for this purpose?
(see
below, counterLock)

A new readonly variable isn't nessecry in all cases(in the below it is, I"ll
get to taht), but its usually good practice. Locking on an instance which
you don't control can be troublesome, because if the instance is held
elsewhere and locked on by other objects, you may end up with a deadlock
condition. Using a private instance of object mitigates that by restricting
access to the lock object and avoiding the possiblity two unrelated pieces
of code will lock on the same object by happenstance.

In your example here, however, counter is a valuetype and therefore a bad
option for locking. lock(and Monitor.Enter\Exit) operate on object
instances. Value Types, however, are copy-by-value and throw object
semantics on their head. Every time you passed counter to the lock statement
you would be locking on a different object and, as a result, end up not
providing any thread safety at all.

Also, since counter is a local, even if it wasn't a value type, the instance
wouldn't be available in any other methods so they couldn't lock on it and
perform synchronization.

There is another good article that discussions synchronization and explains
the issues better than I have at
http://msdn.microsoft.com/msdnmag/issues/03/01/NET/
 
J

Jon Skeet [C# MVP]

Fernando Rodríguez said:
I've been reading the multithreading tutorial at
http://www.yoda.arachsys.com/csharp/threads/locking.shtml (thanks Jon :)and
there's one thing I don't understand.

Why do have to pass a parameter to lock, Monitor.Enter() and Monitor.Exit()?
Why is it necessary to create a new readonly variable for this purpose? (see
below, counterLock)

If you didn't, how would it know what to lock?

It has to be a non-null reference type expression (only objects have
monitors). You *could* use something like typeof(Foo) or "this", but I
recommend against it. See the chapter about "what to lock on" for more
explanation.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top