Reference counting for resource management

Denis Koroskin 2korden at gmail.com
Fri Nov 27 14:47:01 PST 2009


On Sat, 28 Nov 2009 01:27:41 +0300, LMB <lmbarros at gmail.com> wrote:

> Hello,
>
> I've been reading the forums for some time, but this is my first post  
> here :-)
>
> I am trying to create yet another D2 wrapper for SQLite. As usual with  
> many C libraries, SQLite provides us some "objects" and functions to  
> create and destroy them. So, I decided to encapsulate these SQLite  
> objects in a struct, and use reference counting to destroys the objects  
> as soon as I can safely do so.
>
> The problem is that I can't make it work correctly in all situations. It  
> guess that I am not increasing the reference count on every situation in  
> which my object is copied, because I got "negative" reference counts in  
> some tests. But this is just a guess, I am not sure at all.
>
> So, is there any complete example on how to implement reference counting  
> in D2?
>
> I found some discussions about ref counting in D, like Bartoz's nice  
> post  
> (http://bartoszmilewski.wordpress.com/2009/08/19/the-anatomy-of-reference-counting/),  
> but not a complete working example.
>
> If there is no example around, I'd be pleased if someone could give me  
> any advice. This is what one of my wrappers roughly looks like (for  
> brevity, I removed all code not related to reference counting):
>
> struct Database
> {
>    public this(in string fileName)
>    {
>       sqlite3_open(toStringz(fileName), &db_);
>
>       refCount_ = cast(uint*)(malloc(uint.sizeof));
>       *refCount_ = 1;
>    }
>
>    this(this)
>    body
>    {
>       ++(*refCount_);
>    }
>
>    Database opAssign(Database other)
>    {
>       db_ = other.db_;
>       refCount_ = other.refCount_;
>       ++(*refCount_);
>       return this;
>    }
>
>    public ~this()
>    {
>       if (refCount_ !is null)
>       {
>          --(*refCount_);
>
>          if (*refCount_ == 0)
>          {
>             free(refCount_);
>             refCount_ = null;
>             immutable status = sqlite3_close(db_);
>          }
>       }
>    }
>
>    private sqlite3* db_;
>    private uint* refCount_;
> }
>
>
> Thanks!
>
> LMB
>

I attached my implementation of RefCounted pattern. Feel free to use and  
improve it.

Here is an excerpt from a letter I wrote about RefCounted. It covers its  
design, implementation and usage.


There are two templates:
RefCounted and RefObject (see implementation in
net/core/RefCounted.d). They are not classes/structs but rather
templates that are used for being mixed in other classes so that you
don't have to inherit from it. RefObject defines the following
methods:

final public uint referenceCounter() const;
final public void addRef();
final public void releaseRef();
(I'll probably also add final public void destroy(); methods that
would do nothing).

Once you mixin this template into your class, your class instances
become reference-counted (explicitly at this moment), so it could be
used without the other one (see below for details).

Mixins also have useful ability to override default implementation.
For example, destroy() would do nothing by default, and rely on
garbage-collector to recycle memory instead of calling "delete this;".
User may override it and free some resources immediately (e.g.
disconnect from remote host) before memory is recycled.

Automatic reference-counting is achieved using RefCounted template.
It's use is as follows:

struct DriverPtr
{
    mixin RefCountedT!(Driver, DriverPtr);
}

struct LinkPtr
{
    mixin RefCountedT!(Link, LinkPtr);
}

The reason is, again, flexibility. It is possible to override certain
methods when needed. I'll probably also add a default RefCounted
class, something like this:

struct RefCounted!(T)
{
    mixin RefCountedT!(T, RefCounted!(T));
}

Users will be able to use it like this:

alias RefCounted!(Link) LinkPtr;

There are other also other approaches to implement ref-counting
mechanism, but I found this one to be the most flexible one.

The two classes are best used together, but you may use one without
other, two. RefCountedT relies on the following 3 methods:

uint referenceCounter();
void addRef();
void releaseRef();

and it doesn't really care the way they are implemented. The most
convenient way is to use mixin RefObject, though.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: RefCounted.d
Type: application/octet-stream
Size: 1955 bytes
Desc: not available
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20091128/c40ab281/attachment.obj>


More information about the Digitalmars-d mailing list