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.














Reply via email to