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

100% Portable Atomic Reference Counted Pointer...

34 views
Skip to first unread message

Chris Thomasson

unread,
Feb 9, 2008, 1:19:27 PM2/9/08
to
This is a portable strongly thread-safe atomic reference counted pointer
algorithm/implementation which can do things that boost shared_ptr cannot:

http://groups.google.com/group/comp.programming.threads/browse_frm/thread/e5167941d32340c6


Here is the code; it contains a simple example usage:

http://appcore.home.comcast.net/misc/refcount-c.html


which is a slightly tweaked version of the following code:

http://groups.google.com/group/comp.lang.c/msg/a907e51e934f97d6


I fixed a bug wrt the DBG_PRINT macro, and slightly altered the
refcount_create function to allow for setting an initial count; here is the
entire API:
__________________________________________________________
void refcount_create(
refcount* const _this,
refcount_refs refs,
refcount_fp_dtor fp_dtor,
void* state
);


int refcount_acquire(
refcount_local* const _this
);


int refcount_release(
refcount_local* const _this
);


int refcount_copy(
refcount_shared** const _psrc,
refcount_local** const _pdest
);


int refcount_swap(
refcount_shared** const _psrc,
refcount_local** const _pdest
);
__________________________________________________________

I think I am going to build a C++ wrapper on top of this.


Anyway, do any of you have any suggestions or improvements? Is the API good
enough as-is?

Thanks.


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

Chris Thomasson

unread,
Feb 9, 2008, 2:53:59 PM2/9/08
to

"Chris Thomasson" <cri...@comcast.net> wrote in message
news:qp6dnWKChMEjcTDa...@comcast.com...

> This is a portable strongly thread-safe atomic reference counted pointer
> algorithm/implementation which can do things that boost shared_ptr cannot:
[...]

> I fixed a bug wrt the DBG_PRINT macro, and slightly altered the
> refcount_create function to allow for setting an initial count; here is
> the entire API:
> __________________________________________________________
> void refcount_create(
> refcount* const _this,
> refcount_refs refs,
> refcount_fp_dtor fp_dtor,
> void* state
> );
>
>
> int refcount_acquire(
> refcount_local* const _this
> );
>
>
> int refcount_release(
> refcount_local* const _this
> );
>
>
> int refcount_copy(
> refcount_shared** const _psrc,
> refcount_local** const _pdest
> );
>
>
> int refcount_swap(
> refcount_shared** const _psrc,
> refcount_local** const _pdest
> );


Forgot one!


void* refcount_get_state(refcount_local* const _this);


> __________________________________________________________
>
[...]


Chris Thomasson

unread,
Feb 9, 2008, 3:11:43 PM2/9/08
to
Here is quick example of how this can be used in scenarios that simply
demand strong thread-safety:

code-sketch
____________________________________________________________


/* a user-defined item */
typedef struct foo_s {
refcount rc; /* the reference counter */
[...]; /* whatever... */
} foo;


/* foo's dtor */
void foo_dtor(void* state) {
foo* const _this = state;
[tear down foo];
free(_this);
}


/* create a foo object */
refcount_local* foo_ctor(void) {
foo* const _this = malloc(sizeof(*_this));
if (_this) {
/* setup the reference counter up with a count of 1 */
refcount_create(&_this->rc, 1, foo_dtor, _this);

/* setup anything else */

/* return a pointer to the ref-counter */
return &_this->rc;
}
return 0;
}


/* a global shared counter pointer */
static refcount_shared* g_ptr = 0;


/* creates objects and makes them visible to the reader */
void writer() {
refcount_local* l_ptr = 0;
for (;;) {
if (l_ptr = foo_ctor()) {
if (! refcount_swap(&g_ptr, &l_ptr)) {
refcount_release(l_ptr);
}
}
}
}


/* reads objects from the writer */
void reader() {
refcount_local* l_ptr = 0;
for (;;) {
if (! refcount_copy(&g_ptr, &l_ptr)) {
refcount_release(l_ptr);
}
}
}
____________________________________________________________

That usage pattern will not work out with shared_ptr. Create an example of
this, run it and let the sparks fly!

;^)


[...]

Dmitriy V'jukov

unread,
Feb 10, 2008, 8:20:05 AM2/10/08
to
On 9 фев, 23:11, "Chris Thomasson" <cris...@comcast.net> wrote:
> Here is quick example of how this can be used in scenarios that simply
> demand strong thread-safety:
>
> code-sketch
> That usage pattern will not work out with shared_ptr. Create an example of
> this, run it and let the sparks fly!

This will work with boost::shared_ptr with additional external mutex.

Dmitriy V'jukov

George Peter Staplin

unread,
Feb 10, 2008, 7:23:15 PM2/10/08
to


Your code is violating a restriction as I understand it of C and C++.
You shouldn't be using an underscore/_ prefix for identifiers. The _
prefix is reserved for the implementation. So, while you may not run
into problems with most toolchains, the code is formally incorrect.

This is why some people use a _ suffix for instance/class variables
instead.


George

Chris Thomasson

unread,
Feb 10, 2008, 10:23:29 PM2/10/08
to
"George Peter Staplin" <georgeps...@xmission.com> wrote in message
news:foo4hj$1l8$3...@news.xmission.com...
> Chris Thomasson wrote:
[...]

>> __________________________________________________________
>
>
> Your code is violating a restriction as I understand it of C and C++.
> You shouldn't be using an underscore/_ prefix for identifiers. The _
> prefix is reserved for the implementation. So, while you may not run
> into problems with most toolchains, the code is formally incorrect.
>
> This is why some people use a _ suffix for instance/class variables
> instead.

Thank you for looking at the code! I use '_this' out of habit... Perhaps, a
very bad-habit indeed! I will make the proper corrections and repost it. I
was under the impression that a typename, function name, or #define could
not use a leading underscore. I was ignorant to your point that it should
not be used for variable names as well; thanks for your time!

:^)

Chris Thomasson

unread,
Feb 10, 2008, 10:31:32 PM2/10/08
to

"Dmitriy V'jukov" <dvy...@gmail.com> wrote in message
news:be95d70b-c46f-466a...@l16g2000hsh.googlegroups.com...

Yup.

Chris Thomasson

unread,
Feb 10, 2008, 10:32:09 PM2/10/08
to

"Chris Thomasson" <cri...@comcast.net> wrote in message
news:t6qdnRjZQfICIjLa...@comcast.com...

I should have clarified, and said that this will not work with shared_ptr
AS-IS.

Chris Thomasson

unread,
Feb 10, 2008, 11:55:08 PM2/10/08
to

"Chris Thomasson" <cri...@comcast.net> wrote in message
news:btadnXmoQLEhIDLa...@comcast.com...

_this habit manifests itself on USENET; why, well I don't know; I need help!
Look at all the stuff I have posted... There is _this everywhere!

:^(...

Chris Thomasson

unread,
Feb 11, 2008, 1:21:26 AM2/11/08
to

Chris Thomasson

unread,
Feb 11, 2008, 1:25:04 AM2/11/08
to
"George Peter Staplin" <georgeps...@xmission.com> wrote in message
news:foo4hj$1l8$3...@news.xmission.com...
> Chris Thomasson wrote:
[...]
>> __________________________________________________________
>
>
> Your code is violating a restriction as I understand it of C and C++.
> You shouldn't be using an underscore/_ prefix for identifiers. The _
> prefix is reserved for the implementation. So, while you may not run
> into problems with most toolchains, the code is formally incorrect.
>
> This is why some people use a _ suffix for instance/class variables
> instead.

Well, what about a leading underscore followed by a lowercase letter?

Chris Thomasson

unread,
Feb 11, 2008, 1:26:25 AM2/11/08
to

"Chris Thomasson" <cri...@comcast.net> wrote in message
news:mbmdnTlMQ8DtejLa...@comcast.com...

I did not check this with the Standard C... Apparently, a leading underscore
followed by a lowercase letter is okay. I guess I should learn how to read!

:^(...

Chris Thomasson

unread,
Feb 11, 2008, 1:29:03 AM2/11/08
to

"Chris Thomasson" <cri...@comcast.net> wrote in message
news:keadnTUi8pcGdTLa...@comcast.com...

at file-scope that is.

Chris Thomasson

unread,
Feb 11, 2008, 1:30:41 AM2/11/08
to

"Chris Thomasson" <cri...@comcast.net> wrote in message
news:rNydnexKvbmkdDLa...@comcast.com...

I changed it anyway, I should try and get out of the habit.

Chris Thomasson

unread,
Feb 11, 2008, 3:12:35 AM2/11/08
to
Final conclusion:

My habit of using leading underscore in function parameter names is legal.
It is however, rather dangerous to say the least. Thanks to George for
raising the issue as it will help me increase the safety of my coding
skills.

:^)

Gerhard Menzl

unread,
Feb 11, 2008, 5:54:35 AM2/11/08
to
George Peter Staplin wrote:

> Chris Thomasson wrote:
>
>> void refcount_create(
>> refcount* const _this,
>> refcount_refs refs,
>> refcount_fp_dtor fp_dtor,
>> void* state
>> );
>
> Your code is violating a restriction as I understand it of C and C++.
> You shouldn't be using an underscore/_ prefix for identifiers. The _
> prefix is reserved for the implementation. So, while you may not run
> into problems with most toolchains, the code is formally incorrect.
>
> This is why some people use a _ suffix for instance/class variables
> instead.

In C++, identifiers starting with an underscore and followed by a
lowercase letter are fine as long as they are defined in a namespace
other than the global namespace.

--
Gerhard Menzl

Non-spammers may respond to my email address, which is composed of my
full name, separated by a dot, followed by at, followed by "fwz",
followed by a dot, followed by "aero".


X-No-Acknowledgement: yes
X-Replace-Address: yes

Hallvard B Furuseth

unread,
Feb 11, 2008, 8:10:07 AM2/11/08
to
Chris Thomasson writes:

> This is a portable strongly thread-safe atomic reference counted pointer
> algorithm/implementation which can do things that boost shared_ptr
> cannot:
>
> http://groups.google.com/group/comp.programming.threads/browse_frm/thread/e5167941d32340c6
>
>
> Here is the code; it contains a simple example usage:
>
> http://appcore.home.comcast.net/misc/refcount-c.html

I needed to prepend this to get it to compile:

#if !(defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE))
#define _POSIX_C_SOURCE 200112L /* or define _XOPEN_SOURCE as 500 or 600 */
#endif
#include <errno.h>

LOCKTBL_HASHPTR() can be negative, since ptrdiff_t is signed and
negative % positive may be negative. Better to use unsigned long, I
think. Or uintptr_t if available.

const on function arguments is pointless, though I suppose it
can help readability on large functions.

--
Hallvard

Dmitriy V'jukov

unread,
Feb 11, 2008, 9:24:34 AM2/11/08
to
On Feb 11, 4:10 pm, Hallvard B Furuseth <h.b.furus...@usit.uio.no>
wrote:

> const on function arguments is pointless, though I suppose it
> can help readability on large functions.

Const is pointless in function declarations, it doesn't affect
declaration. But it's not pointless in function declarations. This
won't compile:

void f(int const x)
{
x = 0;
}

Dmitriy V'jukov

Chris Thomasson

unread,
Feb 11, 2008, 11:40:56 PM2/11/08
to
"Hallvard B Furuseth" <h.b.fu...@usit.uio.no> wrote in message
news:hbf.2008...@bombur.uio.no...

> Chris Thomasson writes:
>
>> This is a portable strongly thread-safe atomic reference counted pointer
>> algorithm/implementation which can do things that boost shared_ptr
>> cannot:
>>
>> http://groups.google.com/group/comp.programming.threads/browse_frm/thread/e5167941d32340c6
>>
>>
>> Here is the code; it contains a simple example usage:
>>
>> http://appcore.home.comcast.net/misc/refcount-c.html
>
> I needed to prepend this to get it to compile:
>
> #if !(defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE))
> #define _POSIX_C_SOURCE 200112L /* or define _XOPEN_SOURCE as 500 or 600
> */
> #endif
> #include <errno.h>
>
> LOCKTBL_HASHPTR() can be negative, since ptrdiff_t is signed and
> negative % positive may be negative. Better to use unsigned long, I
> think. Or uintptr_t if available.

The fixes are in:

http://appcore.home.comcast.net/misc/refcount-c.html

Thank you!

> const on function arguments is pointless, though I suppose it
> can help readability on large functions.

[...]

:^)

Chris Thomasson

unread,
Feb 11, 2008, 11:52:57 PM2/11/08
to

"Chris Thomasson" <cri...@comcast.net> wrote in message
news:79adnS7SmJn9vCza...@comcast.com...

> "Hallvard B Furuseth" <h.b.fu...@usit.uio.no> wrote in message
> news:hbf.2008...@bombur.uio.no...
>> Chris Thomasson writes:
>>
>>> This is a portable strongly thread-safe atomic reference counted pointer
>>> algorithm/implementation which can do things that boost shared_ptr
>>> cannot:
>>>
>>> http://groups.google.com/group/comp.programming.threads/browse_frm/thread/e5167941d32340c6
>>>
>>>
>>> Here is the code; it contains a simple example usage:
>>>
>>> http://appcore.home.comcast.net/misc/refcount-c.html
>>
>> I needed to prepend this to get it to compile:
>>
>> #if !(defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE))
>> #define _POSIX_C_SOURCE 200112L /* or define _XOPEN_SOURCE as 500 or 600
>> */
>> #endif
>> #include <errno.h>
>>
>> LOCKTBL_HASHPTR() can be negative, since ptrdiff_t is signed and
>> negative % positive may be negative. Better to use unsigned long, I
>> think. Or uintptr_t if available.
>
> The fixes are in:
[...]

I was compiling this on Windows with pthread-win32 emulation. Apparently, it
automatically includes <errno.h> and does not require version macros to get
rwlock pthread API declarations.

Thanks for you time wrt looking at, and attempting to actually compile the
code!

:^D

Chris Thomasson

unread,
Feb 12, 2008, 2:28:26 AM2/12/08
to

"Chris Thomasson" <cri...@comcast.net> wrote in message
news:79adnS7SmJn9vCza...@comcast.com...
> "Hallvard B Furuseth" <h.b.fu...@usit.uio.no> wrote in message
> news:hbf.2008...@bombur.uio.no...
>> Chris Thomasson writes:
>>
>>> This is a portable strongly thread-safe atomic reference counted pointer
>>> algorithm/implementation which can do things that boost shared_ptr
>>> cannot:
>>>
>>> http://groups.google.com/group/comp.programming.threads/browse_frm/thread/e5167941d32340c6
>>>
>>>
>>> Here is the code; it contains a simple example usage:
>>>
>>> http://appcore.home.comcast.net/misc/refcount-c.html
>>
>> I needed to prepend this to get it to compile:
>>
>> #if !(defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE))
>> #define _POSIX_C_SOURCE 200112L /* or define _XOPEN_SOURCE as 500 or 600
>> */
>> #endif
>> #include <errno.h>
>>
>> LOCKTBL_HASHPTR() can be negative, since ptrdiff_t is signed and
>> negative % positive may be negative. Better to use unsigned long, I
>> think. Or uintptr_t if available.
>
> The fixes are in:
[...]


I should alter the hash-function to implement something like the simplistic
following equation:


((((hashword)(mp_this)) * 307) >> 8)


then take the result and % it with the total:

#define HASHPTR(mp_this) (((unsigned char) \
((((hashword)(mp_this)) * 307) >> 8) \
))


#define LOCKTBL_HASHPTR(mp_ptr) \
(HASHPTR(mp_ptr) % LOCKTBL_HASHPTR_DEPTH())


Fix will be in place soon.

Dave Butenhof

unread,
Feb 12, 2008, 9:39:24 AM2/12/08
to
Chris Thomasson wrote:
>
>>> I needed to prepend this to get it to compile:
>>>
>>> #if !(defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE))
>>> #define _POSIX_C_SOURCE 200112L /* or define _XOPEN_SOURCE as 500 or
>>> 600 */
>>> #endif
>>> #include <errno.h>

>>


>> The fixes are in:
> [...]
>
> I was compiling this on Windows with pthread-win32 emulation.
> Apparently, it automatically includes <errno.h> and does not require
> version macros to get rwlock pthread API declarations.

The pragmatic use _POSIX_C_SOURCE depends very much on your code and how
it'll be used.

Technically, any conforming POSIX application MUST define
_POSIX_C_SOURCE to the level of POSIX conformance. Otherwise it's not
portable/conforming, and may not compile everywhere. (As you've seen.)

What happens if you DON'T define it is not specified by the standard. On
many UNIX implementations (as apparently in pthread-win32), in absence
of a more restrictive specification the system will presume you want
access to "everything".

There are some exceptions, as aspects of many traditional UNIX
implementations are incompatible with POSIX/SUS. For example, SUS
specifies something much like traditional SVR signal handler prototypes,
and traditional BSD signal handler prototypes are imcompatible (if they
use more than the original K&R single 'int' argument specifying the
signal number). So BSD-based UNIX implementations generally won't use
SUS conforming signal linkage unless you specify a POSIX or SUS
(_XOPEN_SOURCE) conformance level.

For a lot of code this doesn't matter and it's considered "nice" to let
most code build and run correctly without the required conformance symbols.

The "flip side" is that defining the conformance symbols is required by
the standard to RESTRICT the symbols exposed to the application. This
guarantees that conforming applications can define their own symbols
freely without fear of conflict on some implementations; so it really is
an important rule.

However most traditional UNIX systems, BSD or SVR, have always exposed
symbols that don't conform. Leaving the default conformance environment
"loose" allows all that to, mostly, coexist peacefully with the newer
POSIX and SUS definitions. For example, select() is not a traditional
POSIX function and defining _POSIX_C_SOURCE=199506L, for example, is
required to hide the definition of select(), which caused trouble for
"real world code" that wanted to use threads and select(). Exposing the
non-contradictory POSIX/SUS definitions without
_POSIX_C_SOURCE/_XOPEN_SOURCE was one way to work around this problem.)

The summary is that this issue is really a bit more complex than it
might at first seem. ;-)

And as someone pointed out in another post, C++ namespaces solve this
problem because you can use any names you want in non-default
namespaces, without fear of conflict. POSIX and SUS however are, so far,
entirely C, which doesn't support namespaces.

Chris Thomasson

unread,
Apr 8, 2008, 2:22:37 PM4/8/08
to
"Chris Thomasson" <cri...@comcast.net> wrote in message
news:qp6dnWKChMEjcTDa...@comcast.com...

> This is a portable strongly thread-safe atomic reference counted pointer
> algorithm/implementation which can do things that boost shared_ptr cannot:
>
> http://groups.google.com/group/comp.programming.threads/browse_frm/thread/e5167941d32340c6
>
>
> Here is the code; it contains a simple example usage:
>
> http://appcore.home.comcast.net/misc/refcount-c.html
>
>
> which is a slightly tweaked version of the following code:
>
> http://groups.google.com/group/comp.lang.c/msg/a907e51e934f97d6
>
[...]

You can get an improved lock-hash by adding the following macro:

#define LOCKTBL_HASHPTR_FIXUP(mp_ptr) ( \
(((hashword)(mp_ptr)) * 307) >> 8 \
)


And replacing the existing 'LOCKTBL_HASHPTR' macro with:

#define LOCKTBL_HASHPTR(mp_ptr) ( \
LOCKTBL_HASHPTR_FIXUP(mp_ptr) % LOCKTBL_HASHPTR_DEPTH() \
)

BTW, has anybody tried this out? Can you compile it? Any
suggestions/comments?

0 new messages