Thread.Monitor & references

  • Thread starter Thread starter Brett Robichaud
  • Start date Start date
B

Brett Robichaud

I need to make access to a reference object threadsafe. My natural instinct
was to simply use Monitor.Enter() and Exit(). The problem is that the
object behind the reference changes frequently, so my understanding of
Monitor indicates this would not protect my object. Example:

Bitmap bmp = new Bitmap("x.jpg");
Monitor.Enter(bmp);
bmp = new Bitmap("y.jpg");
Monitor.Exit(bmp);

The above doesn't do when one might expect, correct? My C++ head says to me
that what I really want to do is protect the 'pointer', not thing 'thing
pointed to', since I have no other pointers to this thing. But I'm in C# now
and my head is baffled.

So currently I am using a Mutex to protect this kind of data, but it seems
more klunky. Is there any way to use the slick Monitor (or lock) syntax and
still protect this situation?

-Brett-
 
Why not just declare an invariant companion to the Bitmap

object bitmapGuard = new object();

and lock the guard instead

Regards

Richard Blewett - DevelopMentor
http://staff.develop.com/richardb/weblog

nntp://news.microsoft.com/microsoft.public.dotnet.languages.csharp/<[email protected]>

I need to make access to a reference object threadsafe. My natural instinct
was to simply use Monitor.Enter() and Exit(). The problem is that the
object behind the reference changes frequently, so my understanding of
Monitor indicates this would not protect my object. Example:

Bitmap bmp = new Bitmap("x.jpg");
Monitor.Enter(bmp);
bmp = new Bitmap("y.jpg");
Monitor.Exit(bmp);

The above doesn't do when one might expect, correct? My C++ head says to me
that what I really want to do is protect the 'pointer', not thing 'thing
pointed to', since I have no other pointers to this thing. But I'm in C# now
and my head is baffled.

So currently I am using a Mutex to protect this kind of data, but it seems
more klunky. Is there any way to use the slick Monitor (or lock) syntax and
still protect this situation?

-Brett-



---
Incoming mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.771 / Virus Database: 518 - Release Date: 28/09/2004



[microsoft.public.dotnet.languages.csharp]
 
Brett Robichaud said:
I need to make access to a reference object threadsafe. My natural
instinct
was to simply use Monitor.Enter() and Exit(). The problem is that the
object behind the reference changes frequently, so my understanding of
Monitor indicates this would not protect my object. Example:

Bitmap bmp = new Bitmap("x.jpg");
Monitor.Enter(bmp);
bmp = new Bitmap("y.jpg");
Monitor.Exit(bmp);

Reference assignment is atomic. So, if all you do is reassign the bmp
variable, you don't need to protect it with Monitor.Enter/Exit

If you need to protect a block of code rather than a single assignment, you
should lock on a stable object rather than on a reference that changes all
the time. If you don't have any such object, you can always create one:
static readonly object MyLock = new object();

Bruno.
 
Reference assignment is atomic. So, if all you do is reassign the bmp
variable, you don't need to protect it with Monitor.Enter/Exit

As long as you don't really care if other threads may get the old value
rather than the new one shortly after your assignment (sometimes, this is
harmless). If you care, you should use Monitor.Enter/Exit (or the volatile
keyword).

Bruno.
 
Brett Robichaud said:
I need to make access to a reference object threadsafe. My natural instinct
was to simply use Monitor.Enter() and Exit(). The problem is that the
object behind the reference changes frequently, so my understanding of
Monitor indicates this would not protect my object. Example:

Bitmap bmp = new Bitmap("x.jpg");
Monitor.Enter(bmp);
bmp = new Bitmap("y.jpg");
Monitor.Exit(bmp);

The above doesn't do when one might expect, correct?

That depends on what you might expect :)

It doesn't do what you *want*, certainly.
My C++ head says to me
that what I really want to do is protect the 'pointer', not thing 'thing
pointed to', since I have no other pointers to this thing. But I'm in C# now
and my head is baffled.

So currently I am using a Mutex to protect this kind of data, but it seems
more klunky. Is there any way to use the slick Monitor (or lock) syntax and
still protect this situation?

Use a separate, unchanging reference for locking. See
http://www.pobox.com/~skeet/csharp/threads/lockchoice.shtml for more
information.
 
That would work, but isn't really all that different than the mutex
approach. Though it does allow me to use the lock syntax that I like so
much. I'll give it some thought.

-Brett-

Richard Blewett said:
Why not just declare an invariant companion to the Bitmap

object bitmapGuard = new object();

and lock the guard instead

Regards

Richard Blewett - DevelopMentor
http://staff.develop.com/richardb/weblog
nntp://news.microsoft.com/microsoft.public.dotnet.languages.csharp/ said:
I need to make access to a reference object threadsafe. My natural instinct
was to simply use Monitor.Enter() and Exit(). The problem is that the
object behind the reference changes frequently, so my understanding of
Monitor indicates this would not protect my object. Example:

Bitmap bmp = new Bitmap("x.jpg");
Monitor.Enter(bmp);
bmp = new Bitmap("y.jpg");
Monitor.Exit(bmp);

The above doesn't do when one might expect, correct? My C++ head says to me
that what I really want to do is protect the 'pointer', not thing 'thing
pointed to', since I have no other pointers to this thing. But I'm in C# now
and my head is baffled.

So currently I am using a Mutex to protect this kind of data, but it seems
more klunky. Is there any way to use the slick Monitor (or lock) syntax and
still protect this situation?

-Brett-



---
Incoming mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.771 / Virus Database: 518 - Release Date: 28/09/2004



[microsoft.public.dotnet.languages.csharp]
 
Brett Robichaud said:
That would work, but isn't really all that different than the mutex
approach. Though it does allow me to use the lock syntax that I like so
much. I'll give it some thought.

Locks are also rather cheaper than mutexes, as they're entirely within
the CLR. And yes, lock is great :)
 
No, lock is terrible.

The concept of stack based synchronization primitve acquisition and release is great, and the fact that its's exception proof is great, but the lack of timeout sucks rocks. Infinite timeouts are a great way in multithreaded code to get unrecoverable deadlocks. Its much better to get the first 2 without the last by using a wrapper around Monitor.TryEnter rather than Monitor.Enter (which lock is). Look at Ian Griffiths' TimedLock implementation here

http://www.interact-sw.co.uk/iangblog/2004/04/26/yetmoretimedlocking

Used in conjunction with the using statement it gives stack based, exception proof access and it supports timeouts.

Regards

Richard Blewett - DevelopMentor
http://staff.develop.com/richardb/weblog

nntp://news.microsoft.com/microsoft.public.dotnet.languages.csharp/<[email protected]>

Brett Robichaud said:
That would work, but isn't really all that different than the mutex
approach. Though it does allow me to use the lock syntax that I like so
much. I'll give it some thought.

Locks are also rather cheaper than mutexes, as they're entirely within
the CLR. And yes, lock is great :)

--
Jon Skeet - <[email protected]>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too

---
Incoming mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.771 / Virus Database: 518 - Release Date: 28/09/2004



[microsoft.public.dotnet.languages.csharp]
 
Richard Blewett said:
No, lock is terrible.

The concept of stack based synchronization primitve acquisition and
release is great, and the fact that its's exception proof is great,
but the lack of timeout sucks rocks. Infinite timeouts are a great
way in multithreaded code to get unrecoverable deadlocks.

True - however, given that possibility, I think I'd rather have the
deadlock not recover and the whole process terminate rather than try to
recover, personally. Deadlock is usually the sign of a disastrous
coding mistake rather than anything else. I take your point, but
wouldn't say that lock is terrible :)
Its much
better to get the first 2 without the last by using a wrapper around
Monitor.TryEnter rather than Monitor.Enter (which lock is). Look at
Ian Griffiths' TimedLock implementation here

http://www.interact-sw.co.uk/iangblog/2004/04/26/yetmoretimedlocking

Used in conjunction with the using statement it gives stack based,
exception proof access and it supports timeouts.

That's nice, yes - I'll try to remember it for cases where I would
genuinely find it useful.

What I *do* think is a shame is that Monitor works the way it does,
with any object, rather than Enter etc being instance methods which
need to be called on Monitor instances which are specifically created.
That would get rid of all the code which locks "this" for no good
reason. (It would also save a bit of space for every object which
didn't need to keep a monitor reference for locking purposes, but
that's not the principal reason for it.)
 
The main thing about the TimedLock is rather than trying to work out why part or all of your application isn't responding, it throws an exception that makes it pretty obvious that you probably had a deadlock - and you have half of the story about what was going on (the exception trace).

And in some situations its better to be able to log and recover from a deadlock (granted its a bug) than crash your whole overnight batch run and have to get a 3rd line support dev out of bed to nurse the batch through till morning (assuming any of the operators had noticed the batch process had frozen in the first place)

Regards

Richard Blewett - DevelopMentor
http://staff.develop.com/richardb/weblog

nntp://news.microsoft.com/microsoft.public.dotnet.languages.csharp/<[email protected]>

Richard Blewett said:
No, lock is terrible.

The concept of stack based synchronization primitve acquisition and
release is great, and the fact that its's exception proof is great,
but the lack of timeout sucks rocks. Infinite timeouts are a great
way in multithreaded code to get unrecoverable deadlocks.

True - however, given that possibility, I think I'd rather have the
deadlock not recover and the whole process terminate rather than try to
recover, personally. Deadlock is usually the sign of a disastrous
coding mistake rather than anything else. I take your point, but
wouldn't say that lock is terrible :)
Its much
better to get the first 2 without the last by using a wrapper around
Monitor.TryEnter rather than Monitor.Enter (which lock is). Look at
Ian Griffiths' TimedLock implementation here

http://www.interact-sw.co.uk/iangblog/2004/04/26/yetmoretimedlocking

Used in conjunction with the using statement it gives stack based,
exception proof access and it supports timeouts.

That's nice, yes - I'll try to remember it for cases where I would
genuinely find it useful.

What I *do* think is a shame is that Monitor works the way it does,
with any object, rather than Enter etc being instance methods which
need to be called on Monitor instances which are specifically created.
That would get rid of all the code which locks "this" for no good
reason. (It would also save a bit of space for every object which
didn't need to keep a monitor reference for locking purposes, but
that's not the principal reason for it.)

--
Jon Skeet - <[email protected]>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too

---
Incoming mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.771 / Virus Database: 518 - Release Date: 28/09/2004



[microsoft.public.dotnet.languages.csharp]
 
Richard Blewett said:
The main thing about the TimedLock is rather than trying to work out
why part or all of your application isn't responding, it throws an
exception that makes it pretty obvious that you probably had a
deadlock - and you have half of the story about what was going on
(the exception trace).

True. In a debug situation it's helpful to be able to just pause the
whole process and see what's going on, but in production an exception
is much better for diagnostic purposes than straight deadlock.
And in some situations its better to be able to log and recover from
a deadlock (granted its a bug) than crash your whole overnight batch
run and have to get a 3rd line support dev out of bed to nurse the
batch through till morning (assuming any of the operators had noticed
the batch process had frozen in the first place)

I think it depends - if you've got a major problem like that, the rest
of your overnight batch run might not just fail, but fail in a way
which damages data. I tend to be fairly cautious about this kind of
thing, preferring a complete restart to anything else :)
 
Well yes, you have to code for recovery - you're right that it doesn't happen by magic.

Regards

Richard Blewett - DevelopMentor
http://staff.develop.com/richardb/weblog

nntp://news.microsoft.com/microsoft.public.dotnet.languages.csharp/<[email protected]>

Richard Blewett said:
The main thing about the TimedLock is rather than trying to work out
why part or all of your application isn't responding, it throws an
exception that makes it pretty obvious that you probably had a
deadlock - and you have half of the story about what was going on
(the exception trace).

True. In a debug situation it's helpful to be able to just pause the
whole process and see what's going on, but in production an exception
is much better for diagnostic purposes than straight deadlock.
And in some situations its better to be able to log and recover from
a deadlock (granted its a bug) than crash your whole overnight batch
run and have to get a 3rd line support dev out of bed to nurse the
batch through till morning (assuming any of the operators had noticed
the batch process had frozen in the first place)

I think it depends - if you've got a major problem like that, the rest
of your overnight batch run might not just fail, but fail in a way
which damages data. I tend to be fairly cautious about this kind of
thing, preferring a complete restart to anything else :)

--
Jon Skeet - <[email protected]>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too

---
Incoming mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.771 / Virus Database: 518 - Release Date: 28/09/2004



[microsoft.public.dotnet.languages.csharp]
 
Back
Top