D
Jon Skeet said:...
Having read your example to Bruno, I see what you mean. I guess that
means only Waiting on the "innermost" lock.
Jon Skeet said:...
Yup - I'm going to mention that in a section about Control.Invoke.
Another problem with Control.Invoke is doing something like:
...
Yup, that's coming later.
...
Glad it's of some use. I really *must* get it finished though.
Niki Estner said:Where is that information from? The Docs clearly have a different position:
"Wait releases the lock for the specified object only; if the caller is the
owner of locks on other objects, these locks are not released" (copied from
MSDN Article - Monitor.Wait Method)
Let's assume we have two locks, L1 and L2:
Thread A aquires L1, acquires L2, then waits for L1 (accoring to the docs
releasing L1, not L2)
Thread B acquires L1, tries to acquire L2 -> deadlock (Thread B is waiting
for thread A, and noone else could Pulse L1, so they both wait forever)
Not at all: calling Wait while holding multiple locks isn't good style
anyway; Shared resources should be locked for as short as possible.
There's nothing wrong about callbacks - synchronized containers or older COM
objects will have the same problems in ordinary function calls.
Jon Skeet said:Having read your example to Bruno, I see what you mean. I guess that
means only Waiting on the "innermost" lock.
Niki Estner said:Really? Same example as above, but this time they wait/pulse the innermost
lock:
Thread A aquires L1, acquires L2, then waits for L2 (releasing L2, not L1)
Thread B tries to acquire L1 -> waiting for Thread A, can't pulse L2
You are right: Strictly speaking, this is no deadlock, as some other thread
could acquire and Pulse L2; In practice however, there might well be no
other piece of code that pulses that lock...
Bruno Jouhier said:...
I agree, but the problem is more about "who" writes the code. When you call
a private or non virtual method, you have complete control on the locks that
this method will acquire, but when you call a callback or a virtual method
that may be overriden in assemblies written by someone else, you call some
piece of code that may try to acquire other locks and that will cause
deadlocks if the person who implements this piece of code is not aware that
it is being called in the context of a lock.
There are two ways around it:
a) documentation b) rewrite the code so that the callback is done outside
the lock context. Of course, this does not happen in every piece of code but
this is something that people who write toolkits and framework components
should be aware of.
generalised to "don't acquire lock A within lock B; you can acquire
lock B without having acquired lock A, but that's all". That would get
round the above, but it's a bit harder to keep track of. Mind you,
no-one's trying to say that it's easy to get all this right