digitalmars.D - Reference counting for resource management
- LMB (45/45) Nov 27 2009 Hello,
- LMB (2/5) Nov 27 2009 Ouch! I thought I was posting to the "learn" group. My bad, sorry!
- Denis Koroskin (52/111) Nov 27 2009 I attached my implementation of RefCounted pattern. Feel free to use and...
- Bartosz Milewski (67/129) Nov 29 2009 I don't think you need opAssign. The compiler will automatically use bit...
- Denis Koroskin (8/155) Nov 29 2009 I think RefCounted should be flexible enough to re-usable for other data...
- Bartosz Milewski (8/16) Nov 30 2009 I realize that, but I'm not sure if this would be a library bug or a use...
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-r ference-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
Nov 27 2009
LMB Wrote:Hello, [...]Ouch! I thought I was posting to the "learn" group. My bad, sorry!
Nov 27 2009
On Sat, 28 Nov 2009 01:27:41 +0300, LMB <lmbarros 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-r ference-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! LMBI 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.
Nov 27 2009
I don't think you need opAssign. The compiler will automatically use bitblit and postblit. Here's my implementation of a reference counted thread id structure for comparison: struct Tid { this(HANDLE h) { _h = h; Counter * cnt = cast(Counter *) core.stdc.stdlib.malloc(Counter.sizeof); cnt._n = 1; _cnt = cast(shared Counter *) cnt; } ~this() { release(); } this(this) { _cnt.inc; } // invalidates current Tid object Tid transfer() { Tid tid = { _h, _cnt }; _cnt = null; return tid; } void release() { if (_cnt !is null) { uint newCount = _cnt.dec; if (newCount == 0) { CloseHandle(_h); core.stdc.stdlib.free(cast(Counter *)_cnt); _cnt = null; } } } void start() { assert(_h != INVALID_HANDLE_VALUE); if (ResumeThread(_h) == -1) throw new ThreadException("Error resuming thread"); } void join(bool rethrow = true) { if (_h != INVALID_HANDLE_VALUE) if (WaitForSingleObject(_h, INFINITE) != WAIT_OBJECT_0) throw new ThreadException("Join failed"); } void setPriority() // dummy for now { } private: // Revisit: implement using atomic add struct Counter { uint inc() shared { return ++_n; } uint dec() shared { return --_n; } uint _n = 1; } private: HANDLE _h = INVALID_HANDLE_VALUE; shared Counter * _cnt; } LMB 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-r ference-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
Nov 29 2009
On Mon, 30 Nov 2009 03:19:33 +0300, Bartosz Milewski <bartosz-nospam relisoft.com> wrote:I don't think you need opAssign. The compiler will automatically use bitblit and postblit. Here's my implementation of a reference counted thread id structure for comparison: struct Tid { this(HANDLE h) { _h = h; Counter * cnt = cast(Counter *) core.stdc.stdlib.malloc(Counter.sizeof); cnt._n = 1; _cnt = cast(shared Counter *) cnt; } ~this() { release(); } this(this) { _cnt.inc; } // invalidates current Tid object Tid transfer() { Tid tid = { _h, _cnt }; _cnt = null; return tid; } void release() { if (_cnt !is null) { uint newCount = _cnt.dec; if (newCount == 0) { CloseHandle(_h); core.stdc.stdlib.free(cast(Counter *)_cnt); _cnt = null; } } } void start() { assert(_h != INVALID_HANDLE_VALUE); if (ResumeThread(_h) == -1) throw new ThreadException("Error resuming thread"); } void join(bool rethrow = true) { if (_h != INVALID_HANDLE_VALUE) if (WaitForSingleObject(_h, INFINITE) != WAIT_OBJECT_0) throw new ThreadException("Join failed"); } void setPriority() // dummy for now { } private: // Revisit: implement using atomic add struct Counter { uint inc() shared { return ++_n; } uint dec() shared { return --_n; } uint _n = 1; } private: HANDLE _h = INVALID_HANDLE_VALUE; shared Counter * _cnt; } LMB Wrote:I think RefCounted should be flexible enough to re-usable for other data structures, too (e.g. so that it could be part of Phobos). By the way, your code has a bug: Tid tid; // or release() and exisiting Tid Tid tid2 = tid; // segfault since you don't check if _cnt is null in postblitHello, 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-r ference-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
Nov 29 2009
Denis Koroskin Wrote:I think RefCounted should be flexible enough to re-usable for other data structures, too (e.g. so that it could be part of Phobos).I agree. However this code goes into core, so it can't use Phobos.By the way, your code has a bug: Tid tid; // or release() and exisiting Tid Tid tid2 = tid; // segfault since you don't check if _cnt is null in postblitI realize that, but I'm not sure if this would be a library bug or a user bug. I wish one could just prevent such usage, e.g., by nulling the default constructor: struct Tid { this() = null; ... } This is a more general problem of the absence of user-defined default constructors for structs. This makes perfect sense for PODS, but not for structs that have a destructor (and postblit). Of course, if the default constructor is blocked, you wouldn't be able to have arrays of such structs, which, as a side effect, would eliminate the problem of exceptions thrown from default constructors and array unwinding. It's a bit of a minefield there.
Nov 30 2009