On 7 July 2011 13:10, James Morris <jwm.art.net(a)gmail.com> wrote:
just wondered if any more-experienced-than-i devs
might comment on
this. written in c for c (obviously). i realize it's not portable
outside of GNU GCC (regarding the GCC atomic builtin funcs
__sync_***). meant for a single reader thread and a single writer
thread. comments regarding thread safety very much welcome. thanks in
advance.
james.
I didn't have time to test it before going to work, when posting
earlier, but was hoping someone who might see something immediately
wrong with it might comment. I'm mainly posting back to say it doesn't
work.
It does mostly work, but not always, which is as good as not working
at all. It looses the occasional write. For example my test program
has two threads and two buffers. The first buffer is used for thread 1
to send data to thread 2, and the second is used to send it back
again. With 70 items originating in thread 1, and both buffers large
enough to hold 32 items, 1 item is lost perhaps 1 in 7 program
executions.
I thought a "lock-free" ring buffer was supposed to be the easy solution!
James.
#include "rng_buf.h" /* only prototypes the public functions and
typedefs the struct */
#include <stdlib.h>
#include <string.h>
#include "debug.h"
struct _RingBuffer
{
size_t count;
void** buf;
void** bufend;
void** volatile w;
void** volatile r;
};
RngBuf* rng_buf_new(size_t count)
{
size_t sz = 1;
RngBuf* mb = malloc(sizeof(RngBuf));
if (!mb)
{
return 0;
}
for (sz = 1; sz < count; sz <<= 1)
;
mb->buf = calloc(sz, sizeof(void*));
if (!mb->buf)
{
free(mb);
return 0;
}
mb->count = sz;
mb->bufend = mb->buf + mb->count - 1;
mb->w = mb->buf;
mb->r = mb->buf;
return mb;
}
void rng_buf_free(RngBuf* mb)
{
free(mb->buf);
free(mb);
}
size_t rng_buf_write(RngBuf* mb, const void* data)
{
if (__sync_bool_compare_and_swap(mb->w, 0, data))
{
if (!(__sync_bool_compare_and_swap(&mb->w, mb->bufend, mb->buf)))
__sync_add_and_fetch(&mb->w, sizeof(void*));
return (size_t)1;
}
return (size_t)0;
}
void* rng_buf_read(RngBuf* mb)
{
void* data;
if ((data = __sync_fetch_and_and(mb->r, 0)))
{
if (!__sync_bool_compare_and_swap(&mb->r, mb->bufend, mb->buf))
__sync_add_and_fetch(&mb->r, sizeof(void*));
return data;
}
return NULL;
}
void rng_buf_reset(RngBuf* mb)
{ /* needs work */
mb->r = mb->w = mb->buf;
}