[LAD] a *simple* ring buffer, comments pls?

James Morris jwm.art.net at gmail.com
Fri Jul 8 00:50:57 UTC 2011


On 7 July 2011 13:10, James Morris <jwm.art.net at 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;
> }
>



More information about the Linux-audio-dev mailing list