Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

simple atomic reference counting w/ proxy garbage-collector...

1 view
Skip to first unread message

Chris Thomasson

unread,
Mar 27, 2008, 10:31:36 PM3/27/08
to
Here is how to implement simple strongly thread-safe reference counting
under the protection of basically any proxy garbage-collector. I will use
the following collector impl for the sample code:

http://appcore.home.comcast.net/misc/pc_sample_h_v1.html


<code-sketch>
_____________________________________________________________________
typedef struct foo_obj_s foo_obj;

struct foo_obj_s {
atomicword refcnt;
pc_node pcn;
};


static void foo_obj_dtor(pc_node*);
static foo_obj* foo_obj_ctor(void);
static foo_obj* foo_obj_swap(foo_obj**, foo_obj*);
static foo_obj* foo_obj_acquire(foo_obj**);
static void foo_obj_release(foo_obj*);


static pc_master g_pcm = PC_MASTER_STATICINIT(&g_pcm, foo_obj_dtor);


foo_obj* foo_obj_ctor(void) {
foo_obj* const _this = malloc(sizeof(*_this));
if (_this) {
_this->refcnt = 1;
pc_node_init(&_this->pcn);
}
return _this;
}


void foo_obj_dtor(pc_node* pcn) {
foo_obj* const _this = CONTAINER_OF(pcn, foo_obj, pcn);
free(_this);
}


foo_obj* foo_obj_swap(foo_obj** pdest, foo_obj* src) {
return XCHGPTR(pdest, src);
}


foo_obj* foo_obj_acquire(foo_obj** psrc) {
foo_obj* _this;
pc_region* const pcr = pc_acquire(&g_pcm);
if (_this = LOADPTR(psrc)) {
atomicword cmp = _this->refcnt;
do {
if (! cmp) {
_this = NULL;
break;
}
} while(! CASWORD(&_this->refcnt, &cmp, cmp + 1));
}
pc_release(pcr);
return _this;
}


void foo_obj_release(foo_obj* _this) {
if (XADDWORD(&_this->refcnt, -1) == 1) {
pc_mutate(&g_pcm, &_this->pcn);
}
}
_____________________________________________________________________

That's it. Basically, the trick is that you can never increment a zero
reference count because that means its already been deferred into the
collector.

Here is a simple reader/writer pattern which uses the code above:
_____________________________________________________________________
static foo_obj* g_foo = NULL;


void reader_threads(void) {
for (;;) {
foo_obj* const _this = foo_obj_acquire(&g_foo);
if (_this) {
foo_obj_release(_this);
}
}
}


void writer_threads(void) {
for (;;) {
foo_obj* const _this = foo_obj_ctor();
if (_this) {
foo_obj* prev = foo_obj_swap(&g_foo, _this);
if (prev) {
foo_obj_release(prev);
}
}
}
}
_____________________________________________________________________

Enjoy! :^D


--
Chris M. Thomasson
http://appcore.home.comcast.net

0 new messages