D2 weak references

Leandro Lucarella llucax at gmail.com
Sat Apr 25 09:23:58 PDT 2009


Jason House, el 23 de abril a las 16:48 me escribiste:
> > What I'm not sure is if it's really necessary to do that step. What can go
> > wrong with this simple approach?
> > 
> >      T opCall() {
> >          if (!pool.mark.test(index))
> >              t = null;
> >          return t;
> >      }
> 
> What happens when a collection runs after test returns? You need to copy
> t onto the stack in order to be safe.

You're right, I definitely underestimated the problem. Now I see that this
sequence breaks that implementation:

1) WeakRef.opCall() is called (whick stores a reference to R)
2) The mark bit for R is tested and returns true
3) CPU time is given to other threads with reference to R, which are
   removed
4) Other thread triggers a collection and the world is stopped
5) R gets unmarked because there are no other references to it
6) The world is started
7) WeakRef.opCall() returns R when it should returned null

The problem I see with your original proposal:

    T opCall(){
        T tmp = t; // force future conservative GC scan to find the pointer
        if ( (tmp is null) || (pool.mark[index] == false) ){
            t = null;
            return null;
        }
        tmp = t; // avoid race where t was replaced with new data
        return tmp;
    }

Is that I guess is very likely that 'tmp' get optimized out. Would
declaring it as volatile help? If not, I guess the only way to avoid that
race is add a root manually to the GC (or mark the weakref again as no
NO_SCAN). But both requires synchronization. =(

> > Weakref only reads the reference *if* the mark bit is set, in which case
> > is safe to assume that the object is live.
> 
> How do you check the mark bit? In the sample code, it used the
> reference... Admittedly, one could store the right info to avoid that,
> but it hardly matters.

Right.

> > If the object is garbage, the mark bit is unset and in that case the
> > reference is only *written* (the only race it could happen is the sweep()
> > can be called but in that case the reference is written to null too, so
> > there should be no problem with that, I guess...
> > 
> > As long as the test are successful (t is not overwritten to null), the GC
> > should be able to find the reference in the stack when the function
> > returns.
> > 
> > I'm probably missing something else...
> 
> You're not considering what can happen if the weak ref dereferencing
> thread stops and the rest of the world wreaks havoc on the state of the
> world. A collection could run after checking the mark. If one is careful
> with that, and a copy of t is kept on the stack, will the optimizer
> reuse it? Or will it reread the value? That matters if the finalizer
> runs. The mark bit check can fail from reallocation after deletion.
> 
> I hope that helps...

Yes, thank you.

-- 
Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/
----------------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------------
- Que hacés, ratita?
- Espero un ratito...



More information about the Digitalmars-d mailing list