Thin Lock Implementation

Sean Kelly sean at invisibleduck.org
Tue Aug 19 14:41:37 PDT 2008


Steven Schveighoffer wrote:
> "Bartosz Milewski" wrote
>> Steven Schveighoffer wrote:
>>> Reading further messages in your blog, I see that you expect sharing 
>>> casts to be recursive (to preserve the transitive nature of it).  What if 
>>> two shared objects have references to the same shared object?  If you 
>>> 'unshare' one parent, the other object now is shared, but its 
>>> subcomponent is not shared.  Is that considered ok?
>> No, it's definitely not ok, but unless there is a reference-counting 
>> mechanism in place, we can't do anything about it during casting. However, 
>> the sub-objects will be marked as exclusively owned by the casting thread, 
>> so any attempt from another thread to lock them will result in an 
>> exception. This is true to the spirit of casting in general.
> 
> Yes, it's similar to casting something to invariant when you are not sure 
> that another reference doesn't exist.
> 
> However, in this case, the casting is considered to be an accepted practice 
> (and probably more likely than casting something back and forth from 
> invariant).  Normally, casting has big warning signs all over it, I see this 
> as a commonly used feature (or should it be?).
> 
> I noticed that you have 'locked' and 'unshared' concepts as separate, the 
> former using contention and the latter which is a try-only version.  Is 
> there any enforcement for not using either of these?  For example, if thread 
> A tries to access (without casting) a shared object when thread B has casted 
> it to unshared, does it succeed?
> 
> The thing I'm trying to figure out in all this is, I can see the potential 
> with the implementation you are coming up with for some really cool locking 
> features, yet the 'shared/unshared' plan also has to do with lock-free 
> programming (with fences and stuff, I'm not very familiar with these 
> things).  It looks to me like you can do one or the other, but not both? 
> How do you know which mode you are using a shared variable in?

I think the implication that casting an object to unshared actually 
mutates the "shared" bit within the thin lock bitset.  Something like this:

     shared MyClass c;

     void execThreadA()
     {
         MyClass x = makeLocal( c );
         // 'shared' bit in instance of x is now 0
     }

     T makeLocal(T)( inout T val )
     {
         // Assume that the state of MyClass is appropriately visible to
         // the calling thread because this is a shared object
         shared T tmp = val;
         val = null;
         return cast(unshared) tmp;
     }

If the "val = null" assignment is forgotten in makeLocal then an attempt 
to synchronize on c will throw a SharingException (or whatever it's called).

The benefit of being able to cast away the shared label is clearly for 
performance... if you know that you're the sole owner of a shared object 
then you don't need to lock for otherwise synchronized accesses (so 
long), much like assertUnique for const/invariant data.



Sean



More information about the Digitalmars-d mailing list