www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Reference counting questions

reply Johannes Pfau <spam example.com> writes:
I have some problems understanding the reference counting code in
std.stdio. The reduced code my questions refer to is here:
https://gist.github.com/1099229
(ignore the not-working struct default constructor, that's just to
simplify the code)

in line 5: why is 'refs' initialized to 'uint.max / 2'?

in line 40: what does 'swap(p, rhs.p);' do? Does it decrease the
reference count of the 'original' File and increase the reference count
of the 'new' File? Or does the compiler automatically call the copy
constructor and the destructor when it calls opAssign?

There was some discussion some time ago whether atomic ops have to be
used for ref-counting (something about finalizers of heap allocated
structs?). What happened to that issue?

How's ref-counting supposed to behave with global variables?
--------------------------
module test;
File file;

void main()
{
    file = File("/blah");
    test();
}

void test()
{
    file.read(); //<-- will/should this work?
}
--------------------------

What happens if a ref-counted struct is used as a member in a class?
Will the GC decrease the struct's reference count when the class gets
collected?

Is it possible to add explicit de-referencing to allow a global
struct / struct in class to be manually dereferenced? Is detach meant
to do that? Would this naive implementation work?
https://gist.github.com/1099360

Maybe with the detach addition the copy-ctor and opAssign should throw
on p == null? So that copies of a detached object cannot be made?
-- 
Johannes Pfau
Jul 22 2011
parent reply Jesse Phillips <jessekphillips+d gmail.com> writes:
I don't really think stdio is the place to see modern D ref counting. The 
container class has an Array which is built to use RefCounted. I had 
tried my and at explaining how to use it: http://stackoverflow.com/
questions/4632355/making-a-reference-counted-object-in-d-using-


I'm not really sure if all the details have been worked out. Hopefully I 
explained it correctly and that it gives you an idea of how to make ref 
counting work.
Jul 22 2011
next sibling parent Johannes Pfau <spam example.com> writes:
Jesse Phillips wrote:
I don't really think stdio is the place to see modern D ref counting.
The container class has an Array which is built to use RefCounted. I
had tried my and at explaining how to use it: http://stackoverflow.com/
questions/4632355/making-a-reference-counted-object-in-d-using-


I'm not really sure if all the details have been worked out. Hopefully
I explained it correctly and that it gives you an idea of how to make
ref counting work.
Thanks, I think I understand how to use RefCounted now. But it still leaves this issue: Is it possible to add explicit de-referencing to allow a global struct / struct in class to be manually dereferenced? And it adds a new one: RefCounted calls addRange https://github.com/D-Programming-Language/phobos/blob/master/std/typecons.d#L2304 if the _store size is >= size_t (In fact, as _store already has a size_t for count, addRange will always get called?). This means even if I only want RefCounting for a simple C handle, addRange will be called. I don't understand the use of malloc & free in RefCounted. If addRange is called anyway, why not just use GC.malloc and GC.free? One more thing: The removeRange call uses a different condition: if (hasIndirections!T && RefCounted._store) GC.removeRange(RefCounted._store); if (sz >= size_t.sizeof && p.ptr) GC.addRange(p.ptr, sz); Now say, I store a single byte, wouldn't addRange get called but removeRange not? -- Johannes Pfau
Jul 23 2011
prev sibling parent reply Johannes Pfau <spam example.com> writes:
Jesse Phillips wrote:
I don't really think stdio is the place to see modern D ref counting.
The container class has an Array which is built to use RefCounted. I
had tried my and at explaining how to use it: http://stackoverflow.com/
questions/4632355/making-a-reference-counted-object-in-d-using-


I'm not really sure if all the details have been worked out. Hopefully
I explained it correctly and that it gives you an idea of how to make
ref counting work.
Totally overlooked a 'small' problem with RefCounted: It can't work for cairoD ;-) In cairo the c handle is already reference-counted, so I should use cairo_*_[de]reference(ptr) instead of my own counter, but that can't be done with RefCounted. I think I'll have to adapt the RefCounted implementation for cairoD. But I can still use RefCounted in other projects. BTW: RefCounted also uses std.algorithm.swap in it's opAssign. Still wondering what that's supposed to do. -- Johannes Pfau
Jul 23 2011
parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
I'm don't understand why this code calls the dtor before it calls the ctor:

import std.stdio;
import std.typecons;

void main()
{
    auto wrap1 = Wrapper(1);
}

void free(ref int _payload)
{
    writeln("dealloc");
    _payload = 0;
}

struct Wrapper
{
    struct Payload
    {
        int _payload;
        this(int h) { writeln("alloc"); _payload = h; }
        ~this() { free(_payload); }

        this(this) { assert(false); }
        void opAssign(Wrapper.Payload rhs) { assert(false); }
    }

    private alias RefCounted!(Payload, RefCountedAutoInitialize.no) Data;
    private Data _data;

    this(int h) { _data = Data(h); }
}

prints:
dealloc
alloc
dealloc

What's with the first dtor call?
Jul 24 2011
parent Johannes Pfau <spam example.com> writes:
Andrej Mitrovic wrote:
I'm don't understand why this code calls the dtor before it calls the
ctor:

import std.stdio;
import std.typecons;

void main()
{
    auto wrap1 = Wrapper(1);
}

void free(ref int _payload)
{
    writeln("dealloc");
    _payload = 0;
}

struct Wrapper
{
    struct Payload
    {
        int _payload;
        this(int h) { writeln("alloc"); _payload = h; }
        ~this() { free(_payload); }

        this(this) { assert(false); }
        void opAssign(Wrapper.Payload rhs) { assert(false); }
    }

    private alias RefCounted!(Payload, RefCountedAutoInitialize.no)
 Data; private Data _data;

    this(int h) { _data = Data(h); }
}

prints:
dealloc
alloc
dealloc

What's with the first dtor call?
Strange, I can confirm this behavior and it seems to happen all the time when using RefCounted. I guess this was never an issue for the RefCounted code in phobos (for example std.container.Array) as RefCounted was only used to manage memory, not handles from C libraries. free simply does nothing if called with a null pointer, so this problem never showed up. As a workaround, check your handle against null in the destructor before calling the function to close the handle. -- Johannes Pfau
Jul 25 2011