Difference between __gshared and shared.
Jonathan M Davis via Digitalmars-d
digitalmars-d at puremagic.com
Wed Jul 8 05:21:20 PDT 2015
On Wednesday, 8 July 2015 at 11:02:19 UTC, Márcio Martins wrote:
> If I remember correctly, it was also a pain to use most of
> Phobos with 'shared' without casting left and right.
In general, if you're doing much with a shared object other than
passing it around, you're using shared incorrectly. Various
operations can be done with core.atomic and shared objects, but a
number of operations are outright forbidden by the language, and
to use a non-thread local object correctly (be it __gshared or
shared), you _have_ to protect it with lock except in cases where
you know what you're doing and are _extremely_ careful with
atomic operations. D is effectively trying to force you to not
try and do operations on a shared object unless it's protected by
a lock.
Per TDPL, we're supposed to have synchronized classes which then
strip off the outer layer of shared internally when operating on
their member variables so that the sharedness can be stripped
safely without relying on the programmer getting the locks and
casting right, but synchronized classes have never been
implemented (just synchronized functions), so that doesn't work
at the moment, and stripping off just the outer layer of shared
often isn't enough anyway. So, what you end up having to do is
something along the lines of
synchronized(mutexObj)
{
auto unshared = cast(T)sharedT;
// ...
// do stuff on unshared, since it's considered thread-local,
and normal
// code will work on it.
//...
// make sure that there are no references to unshared before
leaving the
// synchronized block
}
That way, you can use the shared object with normal code as long
as you've protected it properly with a mutex, and the language
prevents you from accidentally operating no the shared object
through the shared reference (which would then be when it's not
protected by a lock). The problem is that unlike with
synchronized classes, you have to explicitly cast away shared
yourself and ensure that no thread-local references to that data
escape the synchronized block, and if you screw it up, you could
have subtle, entertaining bugs, whereas synchronized classes
would be able to guarantee that the outer layer of shared was
safely removed.
What we would ideally have would be a way to do the above code
safely without having to do the cast explicitly and make sure
that that was done correctly, but we haven't figured out how to
do that yet. But this idiom ensures that you operate on shared
objects only when they're protected by a lock. Actually operating
on shared or __gshared objects without locking is just plain
buggy unless you're talking about atomic operations and using
core.atomic properly to deal with that (which isn't necessarily
easy). So, if anything, the fact that folks find shared so
annoying implies that they're trying to write code in a manner
which is not thread-safe. That's not to say that shared doesn't
need to be improved or that there aren't things that you can't do
with it right now that you should be able to, but in general, the
stuff that you can't do with a shared object is stuff that you
shouldn't be doing with a shared object anyway.
- Jonathan M Davis
More information about the Digitalmars-d
mailing list