The "no gc" crowd

Jonathan M Davis jmdavisProg at gmx.com
Thu Oct 10 00:24:28 PDT 2013


On Thursday, October 10, 2013 08:38:31 Jacob Carlborg wrote:
> On 2013-10-10 05:55, Jonathan M Davis wrote:
> > That depends. It works with objects I think (for both shared and
> > immutable), but you definitely have to cast to immutable if you want an
> > immutable array or AA.
> > 
> > Also, casting _away_ shared is going to be a very common operation due to
> > how shared works. In order to use shared, you basically have to protect
> > the variable with a mutex or synchronized block, cast away shared, and
> > then use it as thread-local for whatever you're doing until you release
> > the lock (in which case, you have to be sure that there are no more
> > thread-local references to the shared object). As such, while it might be
> > possible to construct stuff directly as shared, it's going to have to be
> > cast to thread-local just to use it in any meaningful way. So, at this
> > point, I don't think that it even vaguely flies to try and make it so
> > that casting away shared is something that isn't typically done. It's
> > going to be done about as often as shared is used for anything other than
> > very basic stuff.
> 
> What's the reason for casting away "shared", is it to pass it to a
> function that doesn't accept "shared"? The it should be safe if you
> synchronize around the call? But that function could put away, the now ,
> unshared data, which is actually shared and cause problem?

Pretty much nothing accepts shared. At best, templated functions accept 
shared. Certainly, shared doesn't work at all with classes and structs unless 
the type is specifically intended to be used as shared, because you have to 
mark all of its member functions shared to be able to call them. And if you 
want to use that class or struct as both shared and unshared, you have to 
duplicate all of its member functions.

That being the case, the only way in general to use a shared object is to 
protect it with a lock, cast it to thread-local (so that it can actually use 
its member functions or be passed to other functions to be used), and then use 
it. e.g.

synchronized
{
     auto tl = cast(T)mySharedT;
     auto result = tl.foo();
     auto result2 = bar(tl);
}

Obviously, you then have to make sure that there are no thread-local 
references to the shared object when the lock is released, but without casting 
away shared like that, you can't do much of anything with it. So, similar to 
when you cast away const, it's up to you to guarantee that the code doesn't 
violate the type system's guarantees - i.e. that a thread-local variable is 
not accessed by multiple threads. So, you use a lock of some kind to protect 
the shared variable while it's treated as a thread-local variable in order to 
ensure that that guarantee holds. Like with casting away const or with 
@trusted, there's obviously risk in doing this, but there's really no other 
way to use shared at this point - certainly not without it being incredibly 
invasive to your code and forcing code duplication.

- Jonathan M Davis


More information about the Digitalmars-d mailing list