[dmd-concurrency] tail-shared by default?
Steve Schveighoffer
schveiguy at yahoo.com
Fri Jan 8 12:47:50 PST 2010
----- Original Message ----
> From: Walter Bright <walter at digitalmars.com>
>
> Steve Schveighoffer wrote:
> > The only caveat is, we would *need* to change the semantics of shared so that
> you can have a non-shared reference to a shared class instance easily.
>
> That's the so-called "tail-shared" problem. We tried (hard) to make "tail-const"
> work, where the reference is mutable but the contents were const. It sounds
> simple, but just does not work in a language with implicit reference semantics.
Yes, but this isn't const, it is shared. You sometimes want const members or const stack variables. I think you never want the equivalent shared items.
Let's think about how often you actually need to use shared as a storage class:
1) as a global/static variable
2) stack variable? never
3) member variabe? debatable -- you can always create a shared reference to the entire aggregate which seems more logical to me anyway.
What if we make shared *default* to tail-shared for reference and pointer types except for global variables (which will be fully shared), and make it illegal to declare a shared value type on the stack or as a member.
Basically, shared for a global variable means it is a globally shared value, but shared anywhere else means it references either a globally shared value or shared heap data. Any other usage is illegal.
This makes it impossible to share stack data -- good.
This makes it impossible to have shared and local data in the same heap memory block -- good for thread-local heaps.
This makes it easy to declare a local reference to a shared class -- excellent.
This allows having a thread-local heap -- good.
This makes it neigh impossible to declare a thread-local global or static reference to a shared class -- bad for completeness, but is this anticipated to be a common usage?
This means if you want to share delegates, you have to mark the function as a shared closure, and it will always be heap allocated -- an acceptable tradeoff IMO.
examples:
shared int x; // ok, visible to all threads
shared C c; // ok, visible to all threads, the reference itself is shared.
struct S
{
}
class C
{
shared int x; // illegal
shared int *y; // legal, the pointer itself isn't shared -- equivalent to shared(int)* x
shared int[] a; // legal, the array struct itself isn't shared -- equivalent to shared(int)[] a
shared C c; // legal, the reference itself isn't shared
shared S s; // illegal, same as shared int, it's a value type
}
void foo()
{
shared int x; // illegal
shared S s; // illegal
shared C c; // legal, the reference itself isn't shared.
}
void fooShared(shared int* x, immutable int *y) // can only have shareable reference parameters
{
int fn() shared // flags that the entire fooShared function will always be heap-allocated, even if passed to a scope handler.
{
return *x;
}
}
What do you think about this?
-Steve
More information about the dmd-concurrency
mailing list