It probably wasn't very clear from my simplified example, but I'm looking to 
create a shared-reader-one-writer scenario. If I declare MyValue synchronized, 
only one thread can be inside the get() method at a time, which defeats the 
shared-reader requirement. Imagine this is a much larger more complex data 
structure, where get() requires walking through multiple levels of a tree and a 
binary search at the last level.

-- Brian


Bane Wrote:

> I am few days old in playin with D2 and whole shared stuff, so I am probably 
> wrong in something. 
> 
> You should probably declare your example class MyValue synchronized instead 
> of shared. It implies that class is shared too, and this way all methods are 
> synchronized. In D1 you could mix synchronized and non syncrhonized methods 
> in class, in D2 its whole or nothing. This way you don't need _lock var in 
> your example.
> 
> So this would work (i guess)
> 
> synchronized class MyValue {
>      int inc() {
>             return _value++;
>       }
>      int get() {
>             return _value;
>      }
>      private int _value;
> }
> 
> shared MyValue sharedVal;
> 
> void main(){
>   sharedVal = new shared(MyValue );
> }
> 
>  I noticed that in D1 synchronized methods of same class share same lock, 
> while in this D2 example (when the whole class is declared synchronized), 
> each method has its own lock. 
> 
> > Also, is there any documentation on the actual semantics of shared? 
> > http://www.digitalmars.com/d/2.0/attribute.html is a blank on the subject, 
> > and the "migrating to shared" article only talks about simple global state. 
> > What are the actual semantics of shared classes, and how do they interact 
> > with other code? For instance, after much banging of my head against the 
> > desk, I finally wrote a working implementation of a simple shared 
> > multi-reader var. Obviously there are better ways to do a simple shared 
> > incrementing counter, this is just a first experiment working toward a 
> > shared mutable 512MB trie data structure that we have in our app's current 
> > C++ implementation:
> > 
> > > shared class MyValue {
> > >     this() {
> > >         _lock = cast(shared)new ReadWriteMutex;
> > >     }
> > > 
> > >     int inc() {
> > >         synchronized((cast(ReadWriteMutex)_lock).writer) {
> > >             return _value++;
> > >         }
> > >     }
> > > 
> > >     int get() {
> > >         synchronized((cast(ReadWriteMutex)_lock).reader) {
> > >             return _value;
> > >         }
> > >     }
> > > 
> > >     private ReadWriteMutex _lock;
> > >     private int _value;
> > > }
> > > 
> > > shared MyValue sharedVal;
> > > ... seems to behave correctly with multiple threads reading and writing 
> > > ...
> > 
> > So I can maybe understand the cast(shared) in the ctor. But I have to admit 
> > I have absolutely no idea why I had to cast away the shared attribute in 
> > the inc/get methods. Is there any documentation on what's really going on 
> > in the compiler here? It's a shared method, accessing a shared instance 
> > var, why the cast? Is the compiler upset about something in the definition 
> > of ReadWriteMutex itself?
> > 
> > Also, how would one implement this as a struct? My postblit op generates 
> > compiler errors about casting between shared/unshared MyValue:
> > 
> > > shared struct MyValue {
> > >    this(this) { _lock = cast(shared) new ReadWriteMutex; } // ERROR
> > >    ... same as above ...
> > > }
> > 
> > I recognize the possible race conditions here, but there has to be *some* 
> > way to implement a postblit op on a shared struct?
> > 
> > I hope this doesn't come across as empty complaining, I'm happy to help 
> > improve the documentation if I can.
> 

Reply via email to