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