Some missing things in the current threading implementation

Michel Fortin michel.fortin at michelf.com
Sun Sep 12 08:00:17 PDT 2010


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 
<ludwig at informatik.uni-luebeck.de> 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
michel.fortin at michelf.com
http://michelf.com/



More information about the Digitalmars-d mailing list