I must say I agree with most of your observations. Here are some comments...
On 2010-09-12 09:35:42 -0400, Sönke Ludwig
<[email protected]> said:
3. everything in implicit
This may seem kind of counter-intuitive, but using 'synchronized'
classes and features like setSameMutex - which are deadly necessary, it
is stupid to neglect the importance of lock based threading in an
object oriented environment - creates a feeling of climbing without a
safety rope. Not stating how you really want to synchronize/lock and
not being able to directly read from the code how this is really done
just leaves a black-box feeling. This in turn means threading newcomers
will not be educated, they just use the system somehow and it magically
works. But as soon as you get problems such as deadlocks, you suddenly
have to understand the details and in this moment you have to read up
and remember everything that is going on in the background - plus
everything you would have to know about threading/synchronization in C.
I'm not sure if this is the right course here or if there is any better
one.
I'm a little uncomfortable with implicit synchronization too.
Ideally you should do as little as possible from inside a synchronized
statement, and be careful about what functions you call (especially if
they take some other lock). But the way synchronized classes work, they
basically force you to do the reverse -- put everything under the lock
-- and you don't have much control over it. Implicit synchronization is
good for the simple getter/setter case, but for longer functions they
essentially encourage a bad practice.
6. temporary unlock
There are often situations when you do lock-based programming, in
which you need to temporarily unlock your mutex, perform some time
consuming external task (disk i/o, ...) and then reaquire the mutex.
For this feature, which is really important also because it is really
difficult and dirty to work around it, needs language support, could be
something like the inverse of a synchronized {} scope or the
possibility to define a special kind of private member function that
unlocks the mutex. Then, inside whose blocks the compiler of course has
to make sure that the appropriate access rules are not broken (could be
as conservative as disallowing access to any class member).
Well, you can work around this by making another shared class wrapping
the synchronized class and making things you want to happen in a
synchronized block functions of the synchronized class. But that
certainly is a lot of trouble. I'd tend to say implicit synchronization
is the problem.
9. unique
Unique objects or chunks of data are really important not only to be
able to check that a cast to 'immutable' is correct, but also to allow
for passing objects to another thread for computations without making a
superfluous copy or doing superfluous computation.
Indeed, no-aliasing guaranties are important and useful, and not only
for multithreading. But unique as a type modifier also introduce other
complexities to the language, and I can understand why it was chosen
not to add it to D2. I still wish we had it.
11. holes in the system
It seems like there are a lot of ways in which you can still slip in
non-shared data into a shared context.
Your examples are just small bugs in spawn. They'll eventually get fixed.
If you want a real big hole in the type system, look at the destructor problem.
<http://d.puremagic.com/issues/show_bug.cgi?id=4621>
Some examples of bugs that slip by because of it:
<http://d.puremagic.com/issues/show_bug.cgi?id=4624>
12. more practical examples need to be considered
[...]
III. multiple threads computing separate parts of an array
If we had a no-aliasing guaranty in the type system (unique), we could
make a "splitter" function that splits a unique array at the right
positions and returns unique chunks which can be accessed independently
by different cores with no race. You could then send each chunk to a
different thread with correctness assured. Without this no-aliasing
guaranty you can still implement this splitter function, but you're
bound to use casts when using it (or suffer the penalty of atomic
operations).
--
Michel Fortin
[email protected]
http://michelf.com/