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/ringbuffer.cc 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: [EMAIL PROTECTED]
