Concurrency.

Timon Gehr timon.gehr at gmx.ch
Mon Nov 28 08:59:24 PST 2011


On 11/28/2011 01:57 PM, Debdatta wrote:
> @Michael,
>
> Thanks for clearing that up. Your post was very informative. :)
>
>>> Actually, the private data of your thread object could be used by other
>>> threads if the MyThread object is accessible from another thread and
>>> someone calls a method on it.
>
> Absolutely! However I presume that any self respecting programmer will not manipulate shared data without planning it, or at least thinking about
> it. :D Any self respecting coder would know about memory boundaries, and not arbitrarily modify shared data.
>

Any self respecting coder only writes correct code. That is why there 
are never software bugs.

>>> Not having default sharing is about providing guaranties, it's about
>>> making thread-safety checkable by the compiler.

Nope, it is mostly about providing safe, efficient and convenient 
_defaults_ (that is why it is called no sharing _by default_).

In C#/Java you have those three options:

1. Your variables are shared, but not that much, because you have no 
clue when or if at all or in what order changes to a variable in one 
thread get propagated to other threads. This is the default, of course!

2. Your variables are shared, and the language guarantees sequential 
consistency of the memory location across threads. To get that you need 
to annotate your variables with volatile. That makes sense because 
variables that are not intended to be shared would suffer from a severe 
and pointless performance hit if they would have to behave the same. 
Now, well then those should not be shared at all, right?

3. Thread Local Storage. This is the most obscure of the three.


In D you have those three options:

1. Your variables are thread local. This guarantees some nice 
properties, like code that was intended to run in a single-threaded 
environment when it was written will behave nicely in a multi-threaded 
environment too, because every thread gets a copy of all global data. 
This is a sane default.

2. Your variables are shared and the language guarantees sequential 
consistency (not implemented in DMD yet afaik). This is the 'shared' 
type modifier. shared is transitive (as opposed to volatile in C#/Java), 
but if you feel like it, you can just cast away shared. (preferably you 
should know that it is safe, but as I understand that is the kind of 
stuff you enjoy a lot.)

3. Your variables are shared, but there is no sequential consistency. 
This is __gshared.


If you have a closer look, you will see that there is a 1 to 1 feature 
correspondence there. Nothing to complain about.

>
> No piece of code can absolutely guarantee threading errors. When you start a thread you are most likely doing it because you want to manipulate
> shared data. If you wanted complete memory isolation, with the only means of communication being messages, you would create processes, not threads.
> I understand that this is an over generalization, and the current no default sharing idiom provides less isolation than processes, yo get the drift.
> :D
>
> Threads within a process, by definition(in this case the os defines them), operate within a shared memory space.

As soon as those threads run on different cores with separate deeply 
nested caching hierarchies, that is just an illusion established by 
message passing on the hardware level.


> I don't understand the need to add
> an extra level of complexity in the code, as well as the compiler, by abstracting something thats inherant to the os.
>

There is no extra level of complexity. On the contrary. TLS by default 
is a very easy concept and it accurately reflects the ideal mental model 
for the hardware. The only thing that gets added is a tiny bit of 
explicitness.


> Its like const correctness. You can write more concise, perfectly working programs without it. and all it gives you is an extra check on whether a
> function will modify something, which I, as a programmer, already know.

Nope, it does not do that. In C++, const correctness means that you 
cannot call a non-const method on a const reference and that const 
methods cannot assign to fields of the 'this' reference (unless they are 
marked as 'mutable', that is). And that is it.

D const can provide some guarantees, especially in pure function 
signatures that enable some compiler optimizations. There is also 
'immutable', that gives much stronger guarantees than const.

Furthermore shared is not like const correctness because it (should) 
actually affect the generated code.


> You may interpret my comments as me not wanting to give up control to the
> compiler. In that sense, even a GC is abstracting something thats inherant to the os. :D But the GC gives a huge return on investment, and I don't
> see how the no default sharing rule does.
>

Nobody is giving up control here. You can use type casts to make the 
compiler shut up, or use __gshared data.
















More information about the Digitalmars-d mailing list