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/

Reply via email to