Re: What exactly shared means?

2015-01-05 Thread via Digitalmars-d-learn
On Saturday, 3 January 2015 at 23:11:08 UTC, Jonathan M Davis via 
Digitalmars-d-learn wrote:
Ideally, you would never cast away shared, and it would be cast 
away for you
by the compiler in sections of code where it can guarantee that 
it's safe to
do so (that was part of the idea behind synchronized classes). 
But that's
incredibly difficult to do, particularly in a useful way, so we 
don't
currently have it. And yes, that sucks, and we definitely want 
to fix it,
but I still think that it's far better than having everything 
be shared by

default like you get in languages like C++ and Java.


Efficient automatic synchronization is difficult, yes. You can 
try to tie groups of entities to a lock, but that will only work 
in some scenarios.


To me it sounds like having everything shared by default is the 
most conservative (safest) approach, and that it would make sense 
to put restrictions on parameters when you need more performance. 
If D's approach should make sense the compiler would allowed to 
elide atomics on members of an object the reference to the object 
is not marked as shared. That can easily go horribly wrong.


I am also not overly happy with D making TLS default. That means 
new threads instantiate a lot of unused memory if the workload is 
heterogeneous (different threads do different type of work). TLS 
only make sense for things that all threads need.


Re: What exactly shared means?

2015-01-05 Thread Jonathan M Davis via Digitalmars-d-learn
On Monday, January 05, 2015 12:59:26 via Digitalmars-d-learn wrote:
 I am also not overly happy with D making TLS default. That means
 new threads instantiate a lot of unused memory if the workload is
 heterogeneous (different threads do different type of work). TLS
 only make sense for things that all threads need.

Well, if you don't like the choice of TLS by default, then you're going to
be unhappy with shared and its related issues regardless. Personally, I
think that having TLS be the default is a fantastic improvement over C++ and
that it results in much cleaner and safer code, especially since the vast
majority of code only lives on one thread anyway if you're dealing with
threads cleanly. But it's definitely true that what we're up to is an
experiment in how to handle TLS and shared storage, and by no means have we
gotten it perfect.

- Jonathan M Davis



Re: What exactly shared means?

2015-01-03 Thread via Digitalmars-d-learn

On Saturday, 3 January 2015 at 13:53:09 UTC, John Colvin wrote:
I think you're talking cross-purposes. thread-local as in TLS 
v.s. thread-local as in not-shared.


I am not talking TLS. TLS is related to object files, not types. 
You don't have shared vs non-shared. You have many different 
relevant situations:


- no other reader or writer
- no other writer
- not shared now, but later
- unknown
- always shared
++


Re: What exactly shared means?

2015-01-03 Thread Jonathan M Davis via Digitalmars-d-learn
On Saturday, January 03, 2015 12:14:54 via Digitalmars-d-learn wrote:
 On Saturday, 3 January 2015 at 00:12:35 UTC, Jonathan M Davis via
 Digitalmars-d-learn wrote:
  In D, if a type is not marked as shared, then it is by
  definition
  thread-local, and the compiler is free to assume that it's
  thread-local.

 I find this to be rather vague. If the compiler exploit this to
 the maximum wouldn't that lead to lots of bugs?

Only if you're declaring shared or __gshared variables and not protecting
them properly or interacting with C or C++ code in a way that doesn't take
their memory model into account. The vast majority of D code won't care one
whit and won't have any problems, because very little of it needs to be
shared, and thread communication most typically is done via message passing
using std.concurrency, not by declaring shared variables. So, the risk of
bugs related to the compiler taking advantage of its knowledge that a
variable is thread-local if not mark as shared is pretty low in most cases.

Yes, there's definitely a risk of bugs if you're casting away shared or
use __gshared and screw it up (which is part of why we'd much rather have a
way for the language to safely strip away shared when it can guarantee that
a shared variable is properly protected), but for the most part, it's not a
problem at all and is _far_ less of a problem than what you get in languages
like C or C++ which default to shared rather than thread-local.

- Jonathan M Davis



Re: What exactly shared means?

2015-01-03 Thread John Colvin via Digitalmars-d-learn
On Saturday, 3 January 2015 at 12:12:47 UTC, Ola Fosheim Grøstad 
wrote:

On Saturday, 3 January 2015 at 10:13:52 UTC, John Colvin wrote:

The Java, C11 and C++11 memory model.


Well...

http://en.cppreference.com/w/cpp/atomic/memory_order


Ok, with the exception of relaxed atomics.



Yes, I was hoping that perhaps you knew more specifics. AFAIK, 
when not restricted by any kind of barriers, SC-DRF does not 
have a particularly significant cost.


I think that even with lock free datastructures such as Intel 
Threaded Building Blocks, you would still gain from using a 
non-synchronizing API where possible. In real code you have 
several layers for functioncalls, so doing this by hand will 
complicate the code.


That isn't what I mean. I was talking about the restrictions that 
the memory model puts on optimising _all_ code, except where 
memory is provably unshared. Things like never creating a write 
where one would not have occurred in a sequentially consistent 
execution of the original source.


Re: What exactly shared means?

2015-01-03 Thread John Colvin via Digitalmars-d-learn
On Saturday, 3 January 2015 at 13:33:21 UTC, Ola Fosheim Grøstad 
wrote:
On Saturday, 3 January 2015 at 12:17:52 UTC, ketmar via 
Digitalmars-d-learn wrote:
why should it? thread locals are... well, local for each 
thread. you
can't access local of different thread without resorting to 
low-level

assembly and OS dependent tricks.


Of course you can, anything that is reachable through any chain 
of pointers/references is effectively shared, not only the 
object you explicitly share.


So when you cast away shared then call a function and that is 
safe in itself, you don't know what happens when someone 
modifies some function deep down in the call chain later on and 
access some private pointer chain and possibly retain a pointer 
to it.


The alternative is to put shared on all parameters in 
libraries or avoid using libraries...


I think you're talking cross-purposes. thread-local as in TLS 
v.s. thread-local as in not-shared.


Re: What exactly shared means?

2015-01-03 Thread via Digitalmars-d-learn
On Saturday, 3 January 2015 at 12:34:10 UTC, Jonathan M Davis via 
Digitalmars-d-learn wrote:
their memory model into account. The vast majority of D code 
won't care one
whit and won't have any problems, because very little of it 
needs to be
shared, and thread communication most typically is done via 
message passing

using std.concurrency, not by declaring shared variables.


I don't agree with this. If you avoid the problem by message 
passing, then you should do like Go and make it a language 
feature. And accept that you loose out on efficiency and restrict 
the application domain.


If you make shared a language feature you also need to back it 
up with semantic analysis and prove that the concept is sound and 
useful (i.e. no need to break encapsulation, not making most 
libraries unusable without unsafe casting etc).


Re: What exactly shared means?

2015-01-03 Thread via Digitalmars-d-learn
On Saturday, 3 January 2015 at 12:17:52 UTC, ketmar via 
Digitalmars-d-learn wrote:
why should it? thread locals are... well, local for each 
thread. you
can't access local of different thread without resorting to 
low-level

assembly and OS dependent tricks.


Of course you can, anything that is reachable through any chain 
of pointers/references is effectively shared, not only the 
object you explicitly share.


So when you cast away shared then call a function and that is 
safe in itself, you don't know what happens when someone modifies 
some function deep down in the call chain later on and access 
some private pointer chain and possibly retain a pointer to it.


The alternative is to put shared on all parameters in libraries 
or avoid using libraries...


Re: What exactly shared means?

2015-01-03 Thread ketmar via Digitalmars-d-learn
On Sat, 03 Jan 2015 12:14:54 +
via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote:

 On Saturday, 3 January 2015 at 00:12:35 UTC, Jonathan M Davis via 
 Digitalmars-d-learn wrote:
  In D, if a type is not marked as shared, then it is by 
  definition
  thread-local, and the compiler is free to assume that it's 
  thread-local.
 
 I find this to be rather vague. If the compiler exploit this to 
 the maximum wouldn't that lead to lots of bugs?

why should it? thread locals are... well, local for each thread. you
can't access local of different thread without resorting to low-level
assembly and OS dependent tricks.


signature.asc
Description: PGP signature


Re: What exactly shared means?

2015-01-03 Thread via Digitalmars-d-learn
On Saturday, 3 January 2015 at 00:12:35 UTC, Jonathan M Davis via 
Digitalmars-d-learn wrote:
In D, if a type is not marked as shared, then it is by 
definition
thread-local, and the compiler is free to assume that it's 
thread-local.


I find this to be rather vague. If the compiler exploit this to 
the maximum wouldn't that lead to lots of bugs?




Re: What exactly shared means?

2015-01-03 Thread via Digitalmars-d-learn

On Saturday, 3 January 2015 at 10:13:52 UTC, John Colvin wrote:

The Java, C11 and C++11 memory model.


Well...

http://en.cppreference.com/w/cpp/atomic/memory_order

Yes, I was hoping that perhaps you knew more specifics. AFAIK, 
when not restricted by any kind of barriers, SC-DRF does not 
have a particularly significant cost.


I think that even with lock free datastructures such as Intel 
Threaded Building Blocks, you would still gain from using a 
non-synchronizing API where possible. In real code you have 
several layers for functioncalls, so doing this by hand will 
complicate the code.


If you can propagate knowledge down the call chain about locality 
and the semantics of object interfaces or clusters of objects, 
then you can relax restrictions on the optimizer and get better 
performance on real-world code. This would be a natural direction 
for D, since it is already encouraging templated code.


The alternative is to hand code this where it matters, but that 
is inconvenient...


Re: What exactly shared means?

2015-01-03 Thread John Colvin via Digitalmars-d-learn
On Saturday, 3 January 2015 at 00:48:23 UTC, Peter Alexander 
wrote:

On Friday, 2 January 2015 at 23:51:05 UTC, John Colvin wrote:
The rule (in C(++) at least) is that all data is assumed to be 
visible and mutable from multiple other threads unless proved 
otherwise. However, given that you do not write a race, the 
compiler will provide full sequential consistency. If you do 
write a race though, all bets are off.


The memory is visible and mutable, but that's pretty much the 
only guarantee you get. Without synchronization, there's no 
guarantee a write made by thread A will ever be seen by thread 
B, and vice versa.


Analogously in D, if a thread modifies a __gshared variable, 
there's no guarantees another thread will ever see that 
modification. The variable isn't thread local, but it's almost 
as if the compiler to treat it that way.


These relaxed guarantees allow the compiler to keep variables 
in registers, and re-order memory writes. These optimizations 
are crucial to performance.


That is exactly how I understood the situation to be, yes.

2 questions I have to absolutely nail this down for good:

Does D assume that local variables are truly thread-local? I.e. 
can the compiler perform optimisations on local references that 
would break SC-DRF without first proving that it does not? 
Another way of putting it is: can a D compiler perform 
optimisations that are normally illegal in modern C(++) and Java?


If the answer to the above is yes, does the same apply to 
explicit use of __gshared variables?


Re: What exactly shared means?

2015-01-03 Thread John Colvin via Digitalmars-d-learn
On Friday, 2 January 2015 at 23:56:44 UTC, Ola Fosheim Grøstad 
wrote:

On Friday, 2 January 2015 at 23:10:46 UTC, John Colvin wrote:

What significant optimisations does SC-DRF actually prevent?


By SC-DRF I assume you mean the Java memory model.


The Java, C11 and C++11 memory model.

AFAIK SCDRF just means that if you syncronize correctly 
(manually) then you will get sequential consistency 
(restriction on the compiler).


That sounds like a correct description of it to me, yes.

Getting rid of the restrictions on the compiler and eliding 
programmer-provided syncronization allows for more 
optimizations on loads, writes, reordering, 
syncronization/refcounting...?


Yes, I was hoping that perhaps you knew more specifics. AFAIK, 
when not restricted by any kind of barriers, SC-DRF does not have 
a particularly significant cost.


Re: What exactly shared means?

2015-01-03 Thread Jonathan M Davis via Digitalmars-d-learn
On Saturday, January 03, 2015 13:39:51 via Digitalmars-d-learn wrote:
 On Saturday, 3 January 2015 at 12:34:10 UTC, Jonathan M Davis via
 Digitalmars-d-learn wrote:
  their memory model into account. The vast majority of D code
  won't care one
  whit and won't have any problems, because very little of it
  needs to be
  shared, and thread communication most typically is done via
  message passing
  using std.concurrency, not by declaring shared variables.

 I don't agree with this. If you avoid the problem by message
 passing, then you should do like Go and make it a language
 feature. And accept that you loose out on efficiency and restrict
 the application domain.

 If you make shared a language feature you also need to back it
 up with semantic analysis and prove that the concept is sound and
 useful (i.e. no need to break encapsulation, not making most
 libraries unusable without unsafe casting etc).

It is far better in general to use message passing to separate threads, but
by no means is it intended that it be the only way to do things in D. It is
a systems language after all. We have synchronized blocks and mutexes. We
have stuff like std.parallelism. We have fibers. There are quite a few ways
to go about having threads communicate and share data. It's just that
message passing is by far the cleanest and safest in most cases, so it's
what most code should be doing. If that's not what fits a particular
program, then there are plenty of other options available. However, that
does tend to mean having to deal with shared more.

And shared is definitely of benefit regardless of whether you're forced to
carefully cast it away some of the time to use it, just like C++'s const is
useful even if it's not actually full-on physical const like D's const is.
But we pretty much all agree that we want better guarantees than that.
Ideally, you would never cast away shared, and it would be cast away for you
by the compiler in sections of code where it can guarantee that it's safe to
do so (that was part of the idea behind synchronized classes). But that's
incredibly difficult to do, particularly in a useful way, so we don't
currently have it. And yes, that sucks, and we definitely want to fix it,
but I still think that it's far better than having everything be shared by
default like you get in languages like C++ and Java.

- Jonathan M Davis



Re: What exactly shared means?

2015-01-02 Thread John Colvin via Digitalmars-d-learn
On Friday, 2 January 2015 at 23:26:57 UTC, Jonathan M Davis via 
Digitalmars-d-learn wrote:
On Friday, January 02, 2015 19:47:50 John Colvin via 
Digitalmars-d-learn wrote:

On Friday, 2 January 2015 at 13:14:14 UTC, Jonathan M Davis via
Digitalmars-d-learn wrote:
 Objects in D default to being thread-local. __gshared and
 shared both make
 it so that they're not thread-local. __gshared does it 
 without

 actually
 changing the type, making it easier to use but also dangerous
 to use,
 because it makes it easy to violate the compiler's 
 guarantees,

 because it'll
 treat it like a thread-local variable with regards to
 optimizations and
 whatnot.

I'm pretty sure that's not true. __gshared corresponds to 
C-style
globals, which are *not* assumed to be thread-local (see 
below).


No, the type system will treat __gshared like a thread-local 
variable. It
gets put in shared memory like a C global would be, but 
__gshared isn't
actually part of the type, so the compiler has no way of 
knowing that it's
anything other than a thread-local variable - which is 
precisely why it's so

dangerous to use it instead of shared. For instance,

__gshared int* foo;

void main()
{
foo = new int;
int* bar = foo;
}

will compile just fine, whereas if you used shared, it wouldn't.

- Jonathan M Davis


I understand that. As far as optimisations and codegen go, that 
is not the same as being able to assume that something is 
thread-local, far from it.


The rule (in C(++) at least) is that all data is assumed to be 
visible and mutable from multiple other threads unless proved 
otherwise. However, given that you do not write a race, the 
compiler will provide full sequential consistency. If you do 
write a race though, all bets are off.


Are you telling me that D does not obey the C(++) memory model? 
That would be a fatal hole in our C(++) interoperability.


AFAIK, the only data in D that the compiler is allowed to assume 
to be thread-local is data that it can prove is thread-local. The 
trivial case is TLS, which is thread-local by definition.


Re: What exactly shared means?

2015-01-02 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, January 02, 2015 19:47:50 John Colvin via Digitalmars-d-learn wrote:
 On Friday, 2 January 2015 at 13:14:14 UTC, Jonathan M Davis via
 Digitalmars-d-learn wrote:
  Objects in D default to being thread-local. __gshared and
  shared both make
  it so that they're not thread-local. __gshared does it without
  actually
  changing the type, making it easier to use but also dangerous
  to use,
  because it makes it easy to violate the compiler's guarantees,
  because it'll
  treat it like a thread-local variable with regards to
  optimizations and
  whatnot.

 I'm pretty sure that's not true. __gshared corresponds to C-style
 globals, which are *not* assumed to be thread-local (see below).

No, the type system will treat __gshared like a thread-local variable. It
gets put in shared memory like a C global would be, but __gshared isn't
actually part of the type, so the compiler has no way of knowing that it's
anything other than a thread-local variable - which is precisely why it's so
dangerous to use it instead of shared. For instance,

__gshared int* foo;

void main()
{
foo = new int;
int* bar = foo;
}

will compile just fine, whereas if you used shared, it wouldn't.

- Jonathan M Davis



Re: What exactly shared means?

2015-01-02 Thread Peter Alexander via Digitalmars-d-learn

On Friday, 2 January 2015 at 23:51:05 UTC, John Colvin wrote:
The rule (in C(++) at least) is that all data is assumed to be 
visible and mutable from multiple other threads unless proved 
otherwise. However, given that you do not write a race, the 
compiler will provide full sequential consistency. If you do 
write a race though, all bets are off.


The memory is visible and mutable, but that's pretty much the 
only guarantee you get. Without synchronization, there's no 
guarantee a write made by thread A will ever be seen by thread B, 
and vice versa.


Analogously in D, if a thread modifies a __gshared variable, 
there's no guarantees another thread will ever see that 
modification. The variable isn't thread local, but it's almost as 
if the compiler to treat it that way.


These relaxed guarantees allow the compiler to keep variables in 
registers, and re-order memory writes. These optimizations are 
crucial to performance.


Re: What exactly shared means?

2015-01-02 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, January 02, 2015 15:32:51 Steven Schveighoffer via 
Digitalmars-d-learn wrote:
 In fact the
 only useful aspect of shared is that data not marked as shared is
 guaranteed thread local.

That and the fact that you're supposed to be able to know which portions of
your program are operating on shared data quite easily that way, as opposed
to it potentially being scattered everywhere through a program like it can
be in languages like C++ or Java. But it definitely doesn't provide any of
the kinds of compiler guarantees that we all wanted it to. The result is
that it's arguably a bit like C++'s const in that it helps, but it really
doesn't ultimately provide strong guarantees. Personally, I think that we're
still far better off using shared the way it is than using __gshared or
being stuck with what C++ and the like have, but there's no question that
it's not where we want it to be.

- Jonathan M Davis



Re: What exactly shared means?

2015-01-02 Thread John Colvin via Digitalmars-d-learn
On Friday, 2 January 2015 at 22:10:36 UTC, Ola Fosheim Grøstad 
wrote:

On Friday, 2 January 2015 at 21:06:03 UTC, John Colvin wrote:
Hmm. I went in to writing that thinking shared isn't so bad. 
Now I've thought about it, it is pretty damn useless. What's 
the point of knowing that data is shared without knowing how 
to safely use it? I guess it protects against completely naive 
usage.


The real issue with shared is that objects may change status 
during runtime based on the state of the program.


What you really want to know is when a parameter is local, 
that is, guaranteed to not be accessed by another thread during 
the execution of the function. If so you open up for 
optimizations.


What significant optimisations does SC-DRF actually prevent?


Re: What exactly shared means?

2015-01-02 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, January 02, 2015 23:51:04 John Colvin via Digitalmars-d-learn wrote:
 AFAIK, the only data in D that the compiler is allowed to assume
 to be thread-local is data that it can prove is thread-local. The
 trivial case is TLS, which is thread-local by definition.

In D, if a type is not marked as shared, then it is by definition
thread-local, and the compiler is free to assume that it's thread-local. If
it's not actually thread-local (e.g. because you cast away shared), then
it's up to you to ensure that no other threads access that data while it's
being referred to via a reference or pointer that's typed as thread-local.
The only exception is immutable, in which case it's implicitly shared,
because it can never change, and there's no need to worry about multiple
threads accessing the data at the same time.

- Jonathan M Davis



Re: What exactly shared means?

2015-01-02 Thread via Digitalmars-d-learn

On Friday, 2 January 2015 at 23:10:46 UTC, John Colvin wrote:

What significant optimisations does SC-DRF actually prevent?


By SC-DRF I assume you mean the Java memory model. AFAIK SCDRF 
just means that if you syncronize correctly (manually) then you 
will get sequential consistency (restriction on the compiler).


Getting rid of the restrictions on the compiler and eliding 
programmer-provided syncronization allows for more optimizations 
on loads, writes, reordering, syncronization/refcounting...?


Re: What exactly shared means?

2015-01-02 Thread John Colvin via Digitalmars-d-learn
On Friday, 2 January 2015 at 20:32:51 UTC, Steven Schveighoffer 
wrote:

On 1/2/15 2:47 PM, John Colvin wrote:



Are you sure about all this optimisation stuff? I had (perhaps 
wrongly)
assumed that __gshared and shared variables in D guaranteed 
Sequential
Consistency for Data Race Free (SCDRF) and nothing more, just 
like all

normal variables in C, C++ and Java.


There is nothing special about __gshared other than where it is 
put.


Real simple test:

__gshared int x;

void main()
{
   int xlocal;
   int *xp = (rand() % 2) ? x; xlocal;

   *xp = 5;
}

tell me how the compiler can possibly know anything about what 
type of data xp points at?


But with shared, the type itself carries the hint that the data 
is shared between threads. At this point, this guarantees 
nothing in terms of races and ordering, which is why shared is 
so useless. In fact the only useful aspect of shared is that 
data not marked as shared is guaranteed thread local.


If I'm correct, then the advice to users would be Use 
__gshared and
pretend you're writing C/C++/Java, or use shared and do 
exactly the same

but with type-system support for your convenience/frustration.


Use __gshared for accessing C globals, and otherwise only if 
you know what you are doing. There are many aspects of D that 
make assumptions based on whether a type is shared or not.


-Steve


Perhaps a more precise statement of affairs would be this:
All variables/data are SC-DRF with the exception of static 
variables and globals, which are thread-local. `shared` exists 
only to express via the type-system the necessity of thread-safe 
usage, without prescribing or implementing said usage.


Hmm. I went in to writing that thinking shared isn't so bad. 
Now I've thought about it, it is pretty damn useless. What's the 
point of knowing that data is shared without knowing how to 
safely use it? I guess it protects against completely naive usage.


Couldn't we have thread-safe access encapsulated within types 
a-la std::atomic?


Re: What exactly shared means?

2015-01-02 Thread John Colvin via Digitalmars-d-learn
On Friday, 2 January 2015 at 13:14:14 UTC, Jonathan M Davis via 
Digitalmars-d-learn wrote:
Objects in D default to being thread-local. __gshared and 
shared both make
it so that they're not thread-local. __gshared does it without 
actually
changing the type, making it easier to use but also dangerous 
to use,
because it makes it easy to violate the compiler's guarantees, 
because it'll
treat it like a thread-local variable with regards to 
optimizations and

whatnot.


I'm pretty sure that's not true. __gshared corresponds to C-style 
globals, which are *not* assumed to be thread-local (see below).




shared does not add any more synchronization or automatic 
mutex-locking or
anything like that than __gshared does (IIRC, there is some 
talk in TDPL
about shared adding memory barriers - which __gshared wouldn't 
do - but that
hasn't been implemented and probably never would be, because it 
would be too
expensive with regards to efficiency). However, unlike 
__gshared, shared
_does_ alter the type of the variable, so the compiler will 
treat it
differently. That way, it won't do stuff like optimize code 
under the
assumption that the object is thread-local like it can do with 
non-shared

objects.


Are you sure about all this optimisation stuff? I had (perhaps 
wrongly) assumed that __gshared and shared variables in D 
guaranteed Sequential Consistency for Data Race Free (SCDRF) and 
nothing more, just like all normal variables in C, C++ and Java.


Thread-local variables (i.e. everything else in D ) could in 
theory be loosened up to allow some *extra* optimisations that 
C/C++/Java etc. don't normally support (because they would risk 
violating SCDRF), but I don't know how much of this is taken 
advantage of currently.


If I'm correct, then the advice to users would be Use __gshared 
and pretend you're writing C/C++/Java, or use shared and do 
exactly the same but with type-system support for your 
convenience/frustration.


Re: What exactly shared means?

2015-01-02 Thread Steven Schveighoffer via Digitalmars-d-learn

On 1/2/15 2:47 PM, John Colvin wrote:



Are you sure about all this optimisation stuff? I had (perhaps wrongly)
assumed that __gshared and shared variables in D guaranteed Sequential
Consistency for Data Race Free (SCDRF) and nothing more, just like all
normal variables in C, C++ and Java.


There is nothing special about __gshared other than where it is put.

Real simple test:

__gshared int x;

void main()
{
   int xlocal;
   int *xp = (rand() % 2) ? x; xlocal;

   *xp = 5;
}

tell me how the compiler can possibly know anything about what type of 
data xp points at?


But with shared, the type itself carries the hint that the data is 
shared between threads. At this point, this guarantees nothing in terms 
of races and ordering, which is why shared is so useless. In fact the 
only useful aspect of shared is that data not marked as shared is 
guaranteed thread local.



If I'm correct, then the advice to users would be Use __gshared and
pretend you're writing C/C++/Java, or use shared and do exactly the same
but with type-system support for your convenience/frustration.


Use __gshared for accessing C globals, and otherwise only if you know 
what you are doing. There are many aspects of D that make assumptions 
based on whether a type is shared or not.


-Steve


Re: What exactly shared means?

2015-01-02 Thread via Digitalmars-d-learn

On Friday, 2 January 2015 at 21:06:03 UTC, John Colvin wrote:
Hmm. I went in to writing that thinking shared isn't so bad. 
Now I've thought about it, it is pretty damn useless. What's 
the point of knowing that data is shared without knowing how to 
safely use it? I guess it protects against completely naive 
usage.


The real issue with shared is that objects may change status 
during runtime based on the state of the program.


What you really want to know is when a parameter is local, that 
is, guaranteed to not be accessed by another thread during the 
execution of the function. If so you open up for optimizations.


Re: What exactly shared means?

2015-01-02 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, January 02, 2015 11:47:46 Daniel Kozak via Digitalmars-d-learn wrote:
 I always think that shared should be use to make variable global
 across threads (similar to __gshared) with some synchronize
 protection. But this code doesn't work (app is stuck on _aaGetX
 or _aaRehash ):

 shared double[size_t] logsA;

 void main() {

  auto logs = new double[1_000_000];

  foreach(i, ref elem; parallel(logs, 4)) {
  elem = log(i + 1.0);
  logsA[i]= elem;
  }
 }


 But when I add synchronized block it is OK:

 shared double[size_t] logsA;

 void main() {

  auto logs = new double[1_000_000];

  foreach(i, ref elem; parallel(logs, 4)) {
  elem = log(i + 1.0);
  synchronized {
  logsA[i]= elem;
  }
  }
 }

Objects in D default to being thread-local. __gshared and shared both make
it so that they're not thread-local. __gshared does it without actually
changing the type, making it easier to use but also dangerous to use,
because it makes it easy to violate the compiler's guarantees, because it'll
treat it like a thread-local variable with regards to optimizations and
whatnot. It's really only meant for use with C global variable declarations,
but plenty of folks end up using it for more, because it avoids having the
compiler complain at them like it does with shared. Regardless, if you use
__gshared, you need to make sure that you protect it against being accessed
by multiple threads at once using mutexes or synchronized blocks or whatnot.

shared does not add any more synchronization or automatic mutex-locking or
anything like that than __gshared does (IIRC, there is some talk in TDPL
about shared adding memory barriers - which __gshared wouldn't do - but that
hasn't been implemented and probably never would be, because it would be too
expensive with regards to efficiency). However, unlike __gshared, shared
_does_ alter the type of the variable, so the compiler will treat it
differently. That way, it won't do stuff like optimize code under the
assumption that the object is thread-local like it can do with non-shared
objects. It makes it clear which objects are thread-local and which aren't
and enforces that with the type system. In principle, this is great, since
it clearly separates thread-local and non-thread local objects and protects
you against treating a non-thread local object as if it were thread-local.
And as long as you're writing code which operates specifically on shared
variables rather than trying to use normal code with them, it works great.
The problem is that you inevitably want to do things like use a function
that takes thread-local variables on a shared object - e.g. if a type is
written to be used as thread-local, then none of its member functions are
shared, and none of them can be used by a shared object, which obviously
makes using such a type as shared to be a bit of a pain.

In principle, D is supposed to provide ways to safely convert shared objects
to thread-local ones - i.e. when the compiler can guarantee that the object
is protected by a mutex or synchronized block or whatnot. The main way that
this was proposed is what TDPL describes with regards to synchronized
classes. The member variables of a synchronized class would be shared, and
protected by the class, since all of its member functions would be
synchronized, and no direct access to the member variables would be allowed,
guaranteeing that any time the member variables were accessed, it would be
within a synchronized function, meaning that the compiler could guarantee
that all access to the member variables was protected by a mutex. So, the
compiler would then be able to safely strip away the outermost layer of
shared, allowing you to theoretically use the member variables with normal
functions.

However, that only strips away the outermost layer (since that's all the
compiler could guarantee was protected), which frequently wouldn't be
enough, and it requires creating entire synchronized types just to use
shared objects. So, the efficacy of the idea is questionable IMHO, much as
the motivation is a good one (only removing shared when the compiler can
guarantee that only one thread can access it). However, synchronized
classes have yet to be implemented (only synchronized functions), so we
don't currently have the ability to have the outermost layer of shared be
stripped away like that. There is currently no place in the language where
the compiler is able to guarantee that a shared object is sufficiently
protected against access from multiple threads at once for it to be able to
automatically remove shared under any circumstances.

The _only_ way to strip it away at this point is to cast it away explicitly.
So, right now, what you're forced to do is something like

shared T foo = funcThatReturnsSharedT();

synchronized(someObj)
{
// be sure at this point that all other code that access foo
// also synchronizes on someObj before accessing 

Re: What exactly shared means?

2015-01-02 Thread Moritz Maxeiner via Digitalmars-d-learn

On Friday, 2 January 2015 at 11:47:47 UTC, Daniel Kozak wrote:
I always think that shared should be use to make variable 
global across threads (similar to __gshared) with some 
synchronize protection. But this code doesn't work (app is 
stuck on _aaGetX or _aaRehash ):



But when I add synchronized block it is OK:



I am not aware of any changes since the following thread (see the 
second post): 
http://forum.dlang.org/thread/brpbjefcgauuzguyi...@forum.dlang.org#post-mailman.679.1336909909.24740.digitalmars-d-learn:40puremagic.com


So AFAIK shared is currently nothing more than a compiler hint 
(despite the documentation suggesting otherwise (Second to last 
paragraph of __gshared doc compares it to shared, see 
http://dlang.org/attribute.html).


My current understanding is that you either use __gshared and 
do your own synchronisation, or you use thread local storage, 
i.e. do not use shared, but I would be happy to be proven wrong 
on that point.


BTW, you can use the following search to find more information 
(It is was I used to find the above linked thread): 
https://www.google.com/?#q=site:forum.dlang.org+shared