Some missing things in the current threading implementation

Sönke Ludwig ludwig at informatik.uni-luebeck.de
Tue Sep 14 23:04:51 PDT 2010


>> 1. spawn and objects
>> 	Spawn only supports 'function' + some bound parameters. Since taking
>> the address of an object method in D always yields a delegate, it is not
>> possible to call class members without a static wrapper function. This
>> can be quite disturbing when working object oriented (C++ obviously has
>> the same problem).
>
> Except in the case of an immutable or shared object this would be unsafe, as it
> would allow implicit sharing.  I do agree, though, that delegates need to be
> allowed if they're immutable or shared delegates.  Right now taking the address of
> a shared/immutable member function doesn't yield a shared/immutable delegate.
> There are bug reports somewhere in Bugzilla on this.
>

Good to know that there are already bug reports. I remember the 
discussion about allowing shared(delegate) or immutable(delegate) and 
this would be a possible solution. However, I still find the idea that 
those attributes are bound to the delegate type awkward and wrong, as a 
delegate is typically supposed to hide away the internally used 
objects/state and this is just a special case for direct member function 
delegates (what about an inline (){ obj.method(); }?). Also const is not 
part of the delegate and does not have to be because it can be checked 
at delegate creation time. But this is probably a topic on its own.

>> 2. error messages
>> 	Right now, error messages just state that there is a shared/unshared
>> mismatch somewhere. For a non-shared-expert, this can be a real bummer.
>> You have to know a lot of implications 'shared' has to be able to
>> correctly interpret these messages and track down the cause. Not very
>> good for a feature that is meant to make threading easier.
>
> Agreed.  Whenever you run into an unreasonably obtuse error message, a bug report
> would be appreciated.  Bug reports related to wrong or extremely obtuse error
> messages are considered "real", though low priority, bugs around here.
>

I will definitely file bug reports when I continue in this area, I just 
wanted to stress how important the error messages are in this part of 
the language, because the root cause is most often very non-obvious 
compared to other type-system errors.

>> 4. steep learning curve - more a high learning wall to climb on
>> 	Resulting from the first points, my feeling tells me that a newcomer,
>> who has not followed the discussions and thoughts about the system here,
>> will see himself standing before a very high barrier of material to
>> learn, before he can actually put anything of it to use. Also I imagine
>> this to be a very painful process because of all the things that you
>> discover are not possible or those error messages that potentially make
>> you banging your head against the wall.
>
> True, but I think this is just a fact of life when dealing with concurrency in
> general.  Gradually (partly due to the help of people like you pointing out the
> relevant issues) the documentation, etc. will improve.

...plus that even for someone who is already experienced with threading 
in other langugages, there is a lot to know now in D if you go the 
shared path instead of the C++/__gshared path.

>
>> 5. advanced synchronization primitives need to be considered
>> 	Things such as core.sync.condition (the most important one) need to be
>> considered in the 'shared'-system. This means there needs to be a
>> condition variable that takes a shared object instead of a mutex or you
>> have to be able to query an objects mutex.
>
> The whole point of D's flagship concurrency model is that you're supposed to use
> message passing for most things.  Therefore, lock-based programming is kind of
> half-heartedly supported.  It sounds like you're looking for a low-level model
> (which is available via core.thread and core.sync, though it isn't the flagship
> model).  std.concurrency is meant to be a high-level model useful for simple, safe
> everyday concurrency, not the **only** be-all-and-end-all model of multithreading
> in D.
>
>> 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).
>
> Again, the point of std.concurrency is to be primarily message passing-based.  It
> really sounds like what you want is a lower-level model.  Again, it's available,
> but it's not considered the flagship model.
>

Agreed that the flagship model is message passing and to a degree I 
think that is quite reasonable (except that object orientation + message 
passing comes a bit too short IMO). However, I think the support for the 
rest is a bit too half hearted if you have to use casts for everything. 
There are quite some low hanging fruits where a simple syntax or library 
extension could increase the flexibility without sacrificing safety or 
complexity.

>> 9. unique
>
> Just tested this, and it doesn't compile.
>

Forgot the 'shared' in that example:

---
import std.concurrency;

synchronized class Test {
	void publicMethod(){
		spawn( function void(shared Test inst){ inst.privateMethod(); }, this );
	}
	
	private void privateMethod(){
	}
}
---

>> 	II. Implementation of a ThreadPool
>
> My std.parallelism module that's currently being reviewed for inclusion in Phobos
> has a thread pool and task parallelism, though it is completely unsafe (i.e. it
> allows implicit sharing and will not be allowed in @safe code).  std.concurrency
> was simply not designed for pull-out-all-stops parallelism, and pull-out-all-stops
> parallelism is inherently harder than basic concurrency to make safe.  I've given
> up making most std.parallelism safe, but I think I may be able to make a few
> islands of it safe.  The question is whether those islands would allow enough
> useful things to be worth the effort.  See the recent safe asynchronous function
> calls thread.  Since it sounds like you need something like this, I'd sincerely
> appreciate your comments on this module.  The docs are at:
>
> http://cis.jhu.edu/~dsimcha/d/phobos/std_parallelism.html
>
> Code is at:
>
> http://dsource.org/projects/scrapple/browser/trunk/parallelFuture/std_parallelism.d
>
>
>> 	III. multiple threads computing separate parts of an array
>
> Also in the proposed std.parallelism module, though completely unsafe because it
> needs to be fast.
>

I will definitely be looking into std.parallelism (I already have a 
thread pool, but that right now is not really sophisticated, mostly 
because of the previous lack of some advanced synchronization primitives).


More information about the Digitalmars-d mailing list