Difference between __gshared and shared.

Jonathan M Davis via Digitalmars-d digitalmars-d at puremagic.com
Wed Jul 8 09:59:06 PDT 2015


On Wednesday, 8 July 2015 at 14:29:56 UTC, Márcio Martins wrote:
> I think a good way to avoid this extra annoyance would be to 
> have shared be implicitly convertible to non-shared, or 
> actually, shared should just be ignored inside synchronized 
> blocks, essentially the net result is that the cast is done 
> implicitly at the beginning of the block.
>
> To solve the wrong mutex problem that Dmitry mentioned, perhaps 
> a declarative approach could be used? I wouldn't mind the extra 
> syntax, as it also provides documentation by giving clarity 
> into which mutexes guard what data. With the implicit 
> stripping/ignoring of shared it would become very succinct as 
> well.

Synchronized classes would be able to remove the outer layer of 
shared, because they can actually guarantee that no one else has 
access to their member variables (e.g. it would be illegal to 
make them public). So, when it locks the mutex on a member 
function call, it can actually guarantee that stripping that 
outer layer of shared is safe. But it can only strip away the 
outer layer, because it can't make any guarantees beyond that.

For shared to work like you're suggesting, the compiler would 
essentially need to make it so that doing _anything_ to a shared 
object when the mutex wasn't locked would be illegal, and I don't 
know how feasible that really is. And even if it could do it, all 
it would be doing would be the same as a synchronized class and 
stripping away the outer layer of shared. But even then, it 
wouldn't be enough, because it has no way of stopping you from 
assigning that partially-unshared object to something and letting 
it escape, whereas with a synchronized class, everything you're 
doing is inside of a member function, so it's encapsulated, 
allowing the compiler to make better guarantees about what you 
are or aren't doing with the object. So, for what you're 
proposing, you pretty much might as well just create a 
synchronized class which uses opDispatch to forward calls to the 
member variable. It's slightly more verbose at the declaration 
site but less verbose wherever you use the object. And 
regardless, it doesn't solve the problem that all that you can 
strip away of shared is the outer layer. I'm not sure that it's 
possible to do any more than that with compiler guarantees.

Another thing to consider is that you might need to lock multiple 
objects with the same mutex or lock multiple mutexes when 
accessing an object, in which case, what you're proposing is 
definitely worse than what we'd get from synchronized classes, 
since they naturally lock multiple items at once (though they 
don't really cover the case where multiple mutexes need to be 
involved except that because all of their functionality is 
encapsulated, it's easier to put the extra locking where it needs 
to be without missing it).

Maybe we need to do something like you're suggesting, but really, 
it doesn't seem like it's improving particularly on synchronized 
classes.

- Jonathan M Davis


More information about the Digitalmars-d mailing list