valid uses of shared

Steven Schveighoffer schveiguy at yahoo.com
Mon Jun 11 07:46:43 PDT 2012


On Mon, 11 Jun 2012 09:39:40 -0400, Artur Skawina <art.08.09 at gmail.com>  
wrote:

> On 06/11/12 14:07, Steven Schveighoffer wrote:
>> However, allocating another heap block to do sharing, in my opinion, is  
>> worth the extra cost.  This way, you have clearly separated what is  
>> shared and what isn't.
>>
>> You can always cast to get around the limitations.
>
> "clearly separating what is shared and what isn't" *is* exactly what
> tagging the data with 'shared' does.

There are special GC considerations for shared as well.  For instance,  
unshared data can go into a "local" heap.

But I feel uneasy passing around pointers to heap data to other threads  
where some of my thread-local data is present.  It's bound to lead to  
unwanted effects.

For example, if I share some piece of my class, and the other thread holds  
onto it forever, it means my class (which may hold large resources that  
aren't shared) will not be dealloced even when there's no reference to it  
outside that piece of shared data.

Also, don't forget, you can cast to get the behavior you desire.  You  
should always be able to work around these limitations with casting (and  
casting unshared to shared should be well-defined for the compiler as long  
as you don't ever treat the data as unshared again, similar to immutable).

I think it's reasonable to make it easier to write good designs, and  
harder to write questionable ones.  There's a lot of rules in D that are  
like that, just the whole notion of marking shared data is one of them.

I want to stress that this idea of preventing member variables from being  
marked shared is not necessarily a *requirement*, it's merely something I  
think fosters good design.  There's nothing technically wrong with it, I  
just think code is better off not doing it.

But marking stack variables as shared I think has to go -- there are too  
many pitfalls, a cast should be required.

>>>> I think a better way to mark progress is to make it an atomic integer  
>>>> type (like Artur has developed).
>>>
>>> Yes. The problem with that however is that I never managed to make this
>>> do the right thing:
>>>
>>>    Atomic!int a; // somewhere in a shared struct/class.
>>>    ...
>>>    int x = s.a;  // OK, access via getter.
>>>    auto y = s.a; // Oops, we just copied the whole struct.
>>>    void f(T)(T arg);
>>>    f(s.a);       // Ditto.
>>>
>>> Which may happen to work for properly aligned small structs because
>>> accessing those are atomic anyway, but is wrong.
>>
>> You can disable copying with @disable this(this);
>
> I wish.
>
>    shared struct S { int x; @disable this(this); }
>    shared S s;
> Error: cannot implicitly convert expression (this) of type shared(S) to S

This *definitely* is a bug.

>
> The post-dec/inc rewriting together with this bug also means you cannot
> prevent the bogus atomic++ operation from succeeding.
>
> And that is not the only problem with 'shared' and structs.
>
> http://www.digitalmars.com/d/archives/digitalmars/D/Disabling_copy_constructor_in_shared_structs_157638.html
> http://www.digitalmars.com/d/archives/digitalmars/D/dtors_in_shared_structs_fail_to_compile_157978.html

Haven't read these, but if there are bugs in the compiler, make sure you  
file those.  @disable this(this) *should* work, if it doesn't its a bug.

-Steve


More information about the Digitalmars-d mailing list