I’ve done a lot of research, looked over Bob’s excellent analysis, and
Hey, thanks!
looked at some practical examples of lockless programming (scary stuff,
don’t do it!), and I think I’ve come up with an API that more closely
matches the use cases.
I’d love to get feedback on this proposal…
Well I’ve been kind of watching to see where this would go but I think
I need make a few comments.
(All these functions are full memory barriers)
/* A struct so people don’t accidentally use normal operations on it */
typedef struct { int value; } SDL_atomic_t;
Since you are going to use this for a reference count value I believe
that the size of the counter should have the same number of bits as
the size of the address. That means that SDL_atomic_t should be 64
bits on 64 bit architectures. Right now it is possible to build a
machine with enough memory that you can have more than 2^32 references
to an item in the heap. Unlikely… sure. But, the choice is to have
as many bits in the reference count as there are in an address or to
test for reference count overflow and return an error flag or throw an
exception when the reference count overflows.
Because int isn’t necessarily 64 bits long on 64 bit machines the
return types of your functions can’t be int. Also, since SDL_atomic_t
is used for reference counts it would make me happier if it were
unsigned. It doesn’t have to be unsigned because I suspect the
smallest item that can be allocated on the heap is more than 2 bytes
long so it is ok to lose half the reference count range to the
negative numbers. It might really have to be unsigned on word
addressable machines with 2^64 words of memory.
Ok, this may seem absurd but it looks like we will hit the point where
2^64 transistors will fit on a “chip” (more likely a cube by then) in
the next 40 years or so (could be 70 years, could be 20). Before you
start laughing about that let me mention the time my boss scolded me
for “wasting” 2 bytes in the year field of a some code I was
writing… that was 33 years ago and… ya’know that seemed reasonable
on a machine with 24Kb of RAM.
Hmmm… Ya’know what? I think there should be an
SDL_AtomicReferenceCount_t, an SDL_AtomicInt_t, and an SDL_AtomicPtr_t
with operators that are reasonable for all of them. Doing that gets
rid of all the size differences. A ptr has sizeof(void *), and int has
sizeof(int), and a reference count has a size that makes sense for the
architecture.
Nice to see this problem being revisited.
Bob PendletonOn Fri, Jan 14, 2011 at 5:10 PM, Sam Lantinga wrote:
/* Set an atomic variable to a value, returning the previous value */
int SDL_AtomicSet(SDL_atomic_t *a, int value);
/* Get the value of an atomic variable */
int SDL_AtomicGet(SDL_atomic_t *a);
/* Add to an atomic variable, returning the previous value */
int SDL_AtomicAdd(SDL_atomic_t *a, int value);
/* Increment an atomic variable used as a reference count */
void SDL_AtomicIncRef(SDL_atomic_t *a);
/* Decrement an atomic variable used as a reference count,
?? returning SDL_TRUE if the variable has reached zero after decrementing
?*/
SDL_bool SDL_AtomicDecRef(SDL_atomic_t *a);
/* Set an atomic variable to a new value if it is currently an old value,
?? returning SDL_TRUE if the value was set.
?? If you don’t know what this function is for, you shouldn’t use it!
*/
SDL_bool SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval);
/* Set a pointer to a new value if it is currently an old value,
?? returning SDL_TRUE if the value was set.
?? If you don’t know what this function is for, you shouldn’t use it!
*/
SDL_bool SDL_AtomicCASPtr(void **a, void *oldval, void *newval);
–
? ? -Sam Lantinga, Founder and President, Galaxy Gameworks LLC
SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
–
±----------------------------------------------------------