Something needs to happen with shared, and soon.

Alex Rønne Petersen alex at lycus.org
Sun Nov 11 10:46:10 PST 2012


Hi,

It's starting to get outright embarrassing to talk to newcomers about 
D's concurrency support because the most fundamental part of it -- the 
shared type qualifier -- does not have well-defined semantics at all.

I'm certainly not alone in being annoyed by this state of affairs: 
http://d.puremagic.com/issues/show_bug.cgi?id=8993

I've posted rants about the state of shared before and, from the 
comments on those, it appears that what most people want shared to do is 
at least one (and usually multiple) of

* make variables global (if appropriate in the context);
* make the wrapped type completely separate from the unwrapped type;
* make all operations be atomic;
* make all operations result in memory barriers.

At a glance, this looks fine. Exactly what you would want for shared 
types in a concurrent setting, right?

Except, not really. I'll try to explain all of the unsolved problems 
with shared below...

First of all, the fact that shared(T) is completely separate from T 
(i.e. no conversions allowed, except for primitive types) is a huge 
usability problem. In practice, it means that 99% of the standard 
library is unusable with shared types. Hell, even most of the runtime 
doesn't work with shared types. I don't know how to best solve this 
particular problem; I'm just pointing it out because anyone who tries to 
do anything non-trivial with shared will invariably run into this.

Second, the idea of making shared insert atomic operations is an 
absolute fallacy. It only makes sense for primitive types for the most 
part, and even for those, what sizes are supported depends on the target 
architecture. A number of ideas have come up to solve this problem:

* We make shared(T) not compile for certain Ts depending on the target 
architecture. I personally think this is a terrible idea because most 
code using shared will not be portable at all.
* We require any architecture D targets to support atomic operations for 
a certain size S at the very least. This is fine for primitives up to 64 
bits in size, but doesn't clear up the situation for larger types (real, 
complex types, cent/ucent, ...).
* We make shared not insert atomic operations at all (thus making it 
kind of useless for anything but documentation).
* (Possibly others I have forgotten; please let me know if this is the 
case.)

I don't think any of these are particularly attractive, to be honest. If 
we do make shared insert atomic operations, we would also have to 
consider the memory ordering of those operations.

Third, we have memory barriers. I strongly suspect that this is a 
misnomer in most cases where people have suggested this; it's generally 
not useful to have a compiler insert barriers because they are used to 
control ordering of load/store operations which is something the 
programmer will want to do explicitly. In any case, the compiler can't 
usefully figure out where to put barriers, so it would just result in 
really bad performance for no apparent gain.

Fourth, there is implementation complexity. If shared is meant to insert 
specialized instructions, it will result in effectively two code paths 
for most code generation in any D compiler (read: maintenance nightmare).

Fifth, it is completely unclear whether casting to and from shared is 
legal (but with a big fat "caution" sign like casting away const) or if 
it's undefined behavior. Making it undefined behavior would further 
increase the usability problem I described above.

And finally, the worst part of all of this? People writing code that 
uses shared today are blindly assuming it actually does the right thing. 
It doesn't. Their code will break on any non-x86 platform. This is an 
absolutely horrifying situation now that ARM, MIPS, and PowerPC are 
starting to become viable targets for D.

Something needs to be done about shared. I don't know what, but the 
current situation is -- and I'm really not exaggerating here -- 
laughable. I think we either need to just make it perfectly clear that 
shared is for documentation purposes and nothing else, or, figure out an 
alternative system to shared, because I don't see shared actually being 
useful for real world work no matter what we do with it.

-- 
Alex Rønne Petersen
alex at lycus.org
http://lycus.org


More information about the Digitalmars-d mailing list