Locking techniques

  • Thread starter Thread starter Laura T.
  • Start date Start date
L

Laura T.

To synchronize thread access to shared objects, I've always used the
lock(shared_object) { } pattern.
I've seen many recommendations and examples where to synchronize use
lock(another_object) { use shared_object; } pattern.

I do not see any reason to have another simple object to lock for since I
can lock the shared object directly.

Are there any deep implications to use shared lock object to guard the
actual shared object, maybe performance oriented?
Which is better, if it can be measured?


TIA,

LT
 
Hi LT,

A recommendation to use the latter approach [lock(another_object)] is
because your code controls who and when locks are applied to to this
object. In the first case, a rogue client may obtain and keep a lock
to the shared_object preventing the other threads from accessing it.

I'm not sure if there is some code deep down in the CLR that would
impact performance and somehow I don't think so. But the latter
approach uses one more object a little more memory than the first.

In my opinion, if you are writing your own application and the
shared_object is a private object, ie no one can access it outside
you're code, then you'll be quite fine using the first approach.

In short, the second approach is safer and less error prone but uses a
bit more memory.

Cheers,
Adam
 
Hi Adam,

For me the first approach lock(shared_object) seemed better since I do not
need to lookup which object guards which. It's easier to remember to lock
the object I need to operate really than to lookup which guard object guards
what. And it makes locking more granular automatically because the
another_object could be used (wrongly) to guard other uses also.
I was more concerned if there could be some CLR internals that makes the
first apporach more inefficient or "dangerous".

Thanks,

LT
 
Adam Cooper said:
Hi LT,

A recommendation to use the latter approach [lock(another_object)] is
because your code controls who and when locks are applied to to this
object. In the first case, a rogue client may obtain and keep a lock
to the shared_object preventing the other threads from accessing it.

I'm not sure if there is some code deep down in the CLR that would
impact performance and somehow I don't think so. But the latter
approach uses one more object a little more memory than the first.

In my opinion, if you are writing your own application and the
shared_object is a private object, ie no one can access it outside
you're code, then you'll be quite fine using the first approach.

In short, the second approach is safer and less error prone but uses a
bit more memory.

Cheers,
Adam

Also, as Singletons are often implemented with static members and methods
there are no 'this' to lock on. Hence, a lock object are needed.

Happy Coding
- Michael S
 
Michael S wrote:

Also, as Singletons are often implemented with static members and methods
there are no 'this' to lock on. Hence, a lock object are needed.

In those cases, typeof(Singleton) is often used to lock on - which is
just as bad as locking on "this".

Jon
 
Laura said:
For me the first approach lock(shared_object) seemed better since I do not
need to lookup which object guards which.

If you don't have a *very* clear understanding about what needs to be
locked in what circumstances, you *will* run into problems.
It's easier to remember to lock
the object I need to operate really than to lookup which guard object guards
what. And it makes locking more granular automatically because the
another_object could be used (wrongly) to guard other uses also.
I was more concerned if there could be some CLR internals that makes the
first apporach more inefficient or "dangerous".

It's dangerous because if you lock on an object and some code within
the implementation of that object decides to lock on itself in another
thread, you could easily run into deadlocks when you didn't need to
have any contention in the first place.

Furthermore, if you take out locks without a clearly documented order,
you can easily deadlock even within a single class.

It sounds like you're really trying to get away from properly analysing
where you need to synchronize which resources. That's very dangerous.

See http://www.pobox.com/~skeet/csharp/lockchoice.shtml for more
information.

Jon
 
Is the URL correct? I get 404

Marc

Jon Skeet said:
If you don't have a *very* clear understanding about what needs to be
locked in what circumstances, you *will* run into problems.


It's dangerous because if you lock on an object and some code within
the implementation of that object decides to lock on itself in another
thread, you could easily run into deadlocks when you didn't need to
have any contention in the first place.

Furthermore, if you take out locks without a clearly documented order,
you can easily deadlock even within a single class.

It sounds like you're really trying to get away from properly analysing
where you need to synchronize which resources. That's very dangerous.

See http://www.pobox.com/~skeet/csharp/lockchoice.shtml for more
information.

Jon
 
Hi Jo,

it's not that I don't have a *very* clear understanding. To have a very
clear understanding, the rules (and parameters) must be as simple as
possibile. Thus, a rule "access to a shared x needs lock of x" seems quite
simple and clear, easier to implement than "access to shared x needs lock
y".

And yes, I agree with you for dangerous, to some extent, but as far as I go,
lock(this) is not even an issue. All objects involved are under our control.
Deadlocks can happen, granted. The simpler the rules, the simpler the lock
ordering will be to avoid catches.

Thanks!

LT
 
Laura said:
There is a MSR publication that seems to approve the use of lock(this) in
many cases.

http://research.microsoft.com/research/pubs/view.aspx?tr_id=921

Interesting that it doesn't really go into *why* that's being used
though - it seems to be used pretty much by default, ignoring the
possibility that other code will lock on the same reference.

I'm sure there are plenty of articles which use lock(this) - but there
are also articles which describe the pitfalls of such an approach.
Here's one by Jeffrey Richter:

http://msdn.microsoft.com/msdnmag/issues/03/01/NET/

Personally I think it was a mistake making all reference types have
monitors - although it's taken me a long time to come to that
conclusion. (I used to think it was a great idea, right back from when
I started Java programming.)

See http://www.pobox.com/~skeet/csharp/threads/alternative.shtml for a
view on how I would have preferred things to work - and an option for
coding that way instead of using plain "lock" statements.

Jon
 
Laura T. said:
it's not that I don't have a *very* clear understanding. To have a very
clear understanding, the rules (and parameters) must be as simple as
possibile. Thus, a rule "access to a shared x needs lock of x" seems quite
simple and clear, easier to implement than "access to shared x needs lock
y".

Except that you don't know what else will be using the same rules, and
thus locking x when you don't expect it to. If your class is the only
thing that knows about reference y, you know nothing else will lock on
it.
And yes, I agree with you for dangerous, to some extent, but as far as I go,
lock(this) is not even an issue. All objects involved are under our control.

So you're not using any framework classes whatsoever, that might choose
to lock on something else that they're passed?
Deadlocks can happen, granted. The simpler the rules, the simpler the lock
ordering will be to avoid catches.

You don't have complete control over the system at this stage though.

Still, if you want to go ahead with something you know is dangerous, of
course I can't stop you. Just don't say you weren't warned about what
constituted best practice :)
 
Back
Top