digitalmars.D - Re: Sharing in D
- Walter Bright <walter nospamm-digitalmars.com> Aug 01 2008
- "Steven Schveighoffer" <schveiguy yahoo.com> Aug 01 2008
- Jason House <jason.james.house gmail.com> Aug 01 2008
- Walter Bright <newshound1 digitalmars.com> Aug 01 2008
- Bruno Medeiros <brunodomedeiros+spam com.gmail> Aug 11 2008
- dsimcha <dsimcha yahoo.com> Aug 11 2008
- bearophile <bearophileHUGS lycos.com> Aug 11 2008
- Sean Kelly <sean invisibleduck.org> Aug 11 2008
- mort <mortm gmail.com> Aug 01 2008
Steven Schveighoffer Wrote:I'm thinking more in the case of functions. If I have a function foo, and I want to pass my shared data version to it, I need to re-implement foo with the parameters as being shared. Imagine a function with several parameters, in which you want to pass a combination of shared/unshared. That's 2^n variations you have to write.
Not necessary, just make them shared. Unshared implicitly converts to shared, so that works. Putting a fence around an unshared read doesn't break anything, etc.I think at the very least, for this to be palatable, there needs to be another modifier that unifies shared and unshared. Similar to how const unifies mutable and invariant.
Shared unifies shared and unshared.
Aug 01 2008
"Walter Bright" wroteSteven Schveighoffer Wrote:I'm thinking more in the case of functions. If I have a function foo, and I want to pass my shared data version to it, I need to re-implement foo with the parameters as being shared. Imagine a function with several parameters, in which you want to pass a combination of shared/unshared. That's 2^n variations you have to write.
Not necessary, just make them shared. Unshared implicitly converts to shared, so that works. Putting a fence around an unshared read doesn't break anything, etc.
I'm assuming you read my previous example, but I'll rewrite it to demonstrate what I'm trying to show: class sharedObj { private int *_x; synchronized shared int x() {return *_x;} synchronized shared int x(int y) {*_x = y;} synchronized shared void rebind(shared int *y) {_x = y;} } shared sharedObj obj; static this() { obj = new sharedObj; } int *x2; void bar() { obj.x = x2; *x2 = 3; // is this supposed to be guaranteed safe? } Now, Let's say you have thread 1 which calls bar. So now thread 1's x2 and obj._x point to the exact same data, which is both viewed as shared and unshared at the same time. Is this something that should be allowed? Would you not make the assumption that you can do whatever you want with what x2 points to without synchronization because it is unshared? Maybe I don't completely understand what you are intending for shared to mean. I was under the impression that 'unshared' means 'lock free', which cannot be enforcable if you can implicitly cast away the 'lock free' aspect of it. ??? -Steve
Aug 01 2008
Steven Schveighoffer Wrote:"Walter Bright" wroteSteven Schveighoffer Wrote:I'm thinking more in the case of functions. If I have a function foo, and I want to pass my shared data version to it, I need to re-implement foo with the parameters as being shared. Imagine a function with several parameters, in which you want to pass a combination of shared/unshared. That's 2^n variations you have to write.
Not necessary, just make them shared. Unshared implicitly converts to shared, so that works. Putting a fence around an unshared read doesn't break anything, etc.
I'm assuming you read my previous example, but I'll rewrite it to demonstrate what I'm trying to show: class sharedObj { private int *_x; synchronized shared int x() {return *_x;} synchronized shared int x(int y) {*_x = y;} synchronized shared void rebind(shared int *y) {_x = y;} } shared sharedObj obj; static this() { obj = new sharedObj; } int *x2; void bar() { obj.x = x2; *x2 = 3; // is this supposed to be guaranteed safe? } Now, Let's say you have thread 1 which calls bar. So now thread 1's x2 and obj._x point to the exact same data, which is both viewed as shared and unshared at the same time. Is this something that should be allowed? Would you not make the assumption that you can do whatever you want with what x2 points to without synchronization because it is unshared? Maybe I don't completely understand what you are intending for shared to mean. I was under the impression that 'unshared' means 'lock free', which cannot be enforcable if you can implicitly cast away the 'lock free' aspect of it. ??? -Steve
Uh oh Steve, you're starting to sound like me! I made the 2^n comment in the context of the const system a while back and now you're looking at how globals might break a transitve data type system... I could have sworn you were the loudest voice against my ideas!
Aug 01 2008
Steven Schveighoffer wrote:Now, Let's say you have thread 1 which calls bar. So now thread 1's x2 and obj._x point to the exact same data, which is both viewed as shared and unshared at the same time. Is this something that should be allowed? Would you not make the assumption that you can do whatever you want with what x2 points to without synchronization because it is unshared? Maybe I don't completely understand what you are intending for shared to mean.
Eh, I think you've got me there. Looks like unshared cannot be implicitly converted to shared.
Aug 01 2008
Walter Bright wrote:Steven Schveighoffer wrote:Now, Let's say you have thread 1 which calls bar. So now thread 1's x2 and obj._x point to the exact same data, which is both viewed as shared and unshared at the same time. Is this something that should be allowed? Would you not make the assumption that you can do whatever you want with what x2 points to without synchronization because it is unshared? Maybe I don't completely understand what you are intending for shared to mean.
Eh, I think you've got me there. Looks like unshared cannot be implicitly converted to shared.
Akin to why const cannot be implicitly converted to invariant, no? -- Bruno Medeiros - Software Developer, MSc. in CS/E graduate http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Aug 11 2008
One thing that recently popped into my mind about the shared/unshared discussion: What about arrays, etc that are manipulated by multiple threads, but in such a way that each thread is guaranteed not to touch the same elements as any other thread, and to never reallocate the array? This is something I actually do, for such things as filling in large matrices. If I understand this proposal correctly, if the array is unshared, multiple threads can't touch it. If it is shared, the compiler will automatically make it synchronized. In this case, the synchronization overhead might be large and unnecessary. If I have each thread write to separate, unshared data structures and merge them together later, then I'm adding needless complexity to my code.
Aug 11 2008
dsimcha:What about arrays, etc that are manipulated by multiple threads, but in such a way that each thread is guaranteed not to touch the same elements as any other thread, and to never reallocate the array?
If you take a slice of an array [a..b] you don't copy data, so if threads can work on adjacent parts you can slice it in parts that are unshared, and then use the whole usliced block of data... Bye, bearophile
Aug 11 2008
== Quote from dsimcha (dsimcha yahoo.com)'s articleOne thing that recently popped into my mind about the shared/unshared discussion: What about arrays, etc that are manipulated by multiple threads, but in such a way that each thread is guaranteed not to touch the same elements as any other thread, and to never reallocate the array? This is something I actually do, for such things as filling in large matrices. If I understand this proposal correctly, if the array is unshared, multiple threads can't touch it. If it is shared, the compiler will automatically make it synchronized. In this case, the synchronization overhead might be large and unnecessary. If I have each thread write to separate, unshared data structures and merge them together later, then I'm adding needless complexity to my code.
For arrays with elements smaller than the bus width or for unaligned arrays there are still word tearing issues, which makes such an approach risky at best. Less importantly, depending on the size and alignment of the array the threads could end up all competing for the same cache line, which would render parallelization of the algorithm largely pointless unless the computation is extremely expensive. It's almost always better to have each thread work on a copy of the data and then merge it later. Sean
Aug 11 2008
Walter Bright Wrote:Shared unifies shared and unshared.
It seems that you want the semantics for shared to be ``allocated on either the shared heap or the local heap'' and for non-shared to be ``allocated on a thread local heap''. Is that right? If so, then it seems the only safe cast is from non-shared to *const* shared. I think that was what Steven's example was meant to demonstrate (though I had trouble following it).
Aug 01 2008









Jason House <jason.james.house gmail.com> 