Le 01/06/2012 14:55, Regan Heath a écrit :
On Thu, 31 May 2012 19:29:27 +0100, Andrei Alexandrescu
<[email protected]> wrote:
On 5/31/12 7:01 AM, Regan Heath wrote:
Sorry, I have no spare time to spare. You're getting free ideas/thoughts
from me, feel free to ignore them.
Thanks. Let me know if I understand correctly that your idea boils
down to "I don't like synchronized, let's deprecate it and get back to
core.sync.mutex and recommend the private thingamaroo." In that case,
I disagree. I believe synchronized has good merits that are being
ignored.
To present this another way..
Your motivation for the construct: "synchronized(a, b, ...)" was to
prevent deadlocks caused by:
[thread1]
synchronized(a)
{
synchronized(b)
{
}
}
[thread2]
synchronized(b)
{
synchronized(a)
{
}
}
right?
Well, this is the same problem expressed several other less-obvious (to
code inspection) ways:
1.
[thread1]
synchronized(a)
{
b.foo(); // where b.foo is { synchronized(this) { ... } }
}
[thread2]
synchronized(b)
{
a.foo(); // where a.foo is { synchronized(this) { ... } }
}
2.
[thread1]
synchronized(a)
{
b.foo(); // where b.foo is synchronized void foo() { ... }
}
[thread2]
synchronized(b)
{
a.foo(); // where a.foo is synchronized void foo() { ... }
}
#1 can be solved (in most/many cases) by doing 2 things, first by
disallowing that idiom completely in favour of synchronized
classes/class methods (which I think TDPL does?), and second by adding
more control as described below in(#2)
#2 can be solved (in most/many cases) by allowing greater control over
who can participate in synchronized statements. If either 'a' or 'b'
were not allowed to participate in a synchronized statement, then either
thread1 or thread2 would be invalid code and a deadlock involving these
2 objects would be impossible(*).
There will still exist some synchronized classes which want to
participate in synchronized statements but I'm thinking/hoping this is
rare and if the default for D is 'not allowed' then it becomes a
conscious choice and we can supply the developer with a warning in the
docs which describe how to do it, introduce the synchronized(a, b, ...)
construct, etc.
From another angle.. I'm guessing it's either impossible or very hard
to detect the 2 cases presented above at compile time? Essentially the
compiler would need to know which code could execute in separate
threads, then determine lock ordering for all shared/lockable objects,
then detect cases of both (lock a, b) and (lock b, a) in separate
threads. Sounds tricky.
R
(*)using synchronized statements - one could still keep a reference to
the other internally and call a synchronized member function from within
a synchronized member function
I think it is unrealistic to prevent all deadlock, unless you can come
up with a radically new approach.
It is still possible to provide interface that prevent common traps.