On Thu, Apr 03, 2003 at 11:31:29AM -0800, Tim Hockin wrote:
courtesy of
paul davis:
you should use a lock free ringbuffer. we will be adding example code
to the example-clients directory soon. existing code is in ardour's
source base (for C++). the example code will be in
example-clients/capture_client.c.
where ardour is
ardour.sf.net. (i doubt there is anything hugely non-C in
the ringbuffer code proper).
maybe it's just me, but I can't find said file...?
hmmm i noticed after i posted that it said, "we will be adding". so
it's not there yet, but it will be eventually. there are examples of
it in the ardour code though.
try looking at
http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/ardour/ardour/libs/pbd/ringb…
ie ( ardour/libs/pbd/ringbuffer.cc ) in the source distribution.
click on the rev 1.2 (view) link.
i think this is the right thing...but don't hold me to it, cause i'm
dumb.
(note that the mlock/unlock stuff is for locking the buffer region
into memory).
below is what i use (i think it works). the primary thing to notice
is that readers and writers are kept in line by the atomicity of
integer assignment (though in general, we should probably declare them
atomic_t or something).
another thing to note is that this allows one writer and one reader to
communicate asynchronously in one direction (where one writer and one
reader may be a group of writers and readers who are synchronous with
respect to their group members). the important thing is that one group
must always be the writers and one group must always be the readers
and they may not switch at any time.
again caveat emptor.
rob
---------------------------------------
es_queue_t *
es_queue_init(int size)
{
es_queue_t * esq;
esq = (es_queue_t *)malloc(sizeof(es_queue_t));
if (esq == NULL) {
return NULL;
}
esq->head = 0;
esq->tail = 0;
esq->size = size;
esq->write_fail_count = 0;
esq->q = (void **)malloc(sizeof(void *)*size);
return esq;
}
void
es_queue_destroy(es_queue_t * esq) {
if (esq == NULL) {
return;
}
if (esq->size != 0 && esq->q != NULL) {
free(esq->q);
esq->q = NULL;
}
free(esq);
return;
}
int
es_queue_write(es_queue_t * esq, void * data)
{
int i;
i = (esq->head+1)%esq->size;
if (i == esq->tail) {
esq->write_fail_count++;
return -1;
}
esq->q[i] = data;
esq->head = i;
return 1;
}
/* this function returns NULL on no data available
*/
void *
es_queue_read(es_queue_t * esq)
{
void * data;
int i;
if (esq->head == esq->tail) {
return NULL;
}
i = (esq->tail+1)%esq->size;
data = esq->q[i];
// this needs to go last to assure that our value isn't overwritten
// until we actually have it out
esq->tail = i;
return data;
}
#ifdef TEST
int
main(int argc, char ** argv)
{
es_queue_t * esq;
int i, x;
fprintf(stderr, "starting test\n");
esq = es_queue_init(128);
fprintf(stderr, "writing\n");
fprintf(stderr, "%i %i\n", esq->head, esq->tail);
for (i = 0; i < 64; i++) {
es_queue_write(esq, (void *)i);
}
fprintf(stderr, "%i %i\n", esq->head, esq->tail);
fprintf(stderr, "reading\n");
for (i = 0; i < 64; i++) {
x = (int)es_queue_read(esq);
if (i!=0 && i%10 == 0 ) {
fprintf(stderr, "\n");
}
fprintf(stderr, "%2d, ", x);
}
fprintf(stderr, "\n");
fprintf(stderr, "overruns: %i\n", esq->write_fail_count);
fprintf(stderr, "writing and reading\n");
for (i = 0; i < 128; i++) {
es_queue_write(esq, (void *)i);
x = (int)es_queue_read(esq);
if (i!=0 && i%10 == 0 ) {
fprintf(stderr, "\n");
}
fprintf(stderr, "%3d, ", x);
}
fprintf(stderr, "\n");
fprintf(stderr, "reading from empty queue\n");
for (i = 0; i < 128; i++) {
x = (int)es_queue_read(esq);
if (i!=0 && i%10 == 0 ) {
fprintf(stderr, "\n");
}
fprintf(stderr, "%d, ", x);
}
fprintf(stderr, "\n");
fprintf(stderr, "done with tests\n");
return 0;
}
-----------------------------------------------------
----
Robert Melby
Georgia Institute of Technology, Atlanta Georgia, 30332
uucp: ...!{decvax,hplabs,ncar,purdue,rutgers}!gatech!prism!gt4255a
Internet: async(a)cc.gatech.edu