uint16_t push_count;
uint16_t pop_count;
int circ_gbuf_free_space(circ_gbuf_t *circ_buf)
{
int total;
total = circ_buf->push_count - circ_buf->pop_count;
if (total < 0)
total += (2 * circ_buf->size);
return circ_buf->size - total;
}
int circ_gbuf_pop(circ_gbuf_t *circ_buf, void *elem, int read_only)
{
...
total = circ_buf->push_count - circ_buf->pop_count;
if (total < 0)
total += (2 * circ_buf->size);
...
}
int circ_gbuf_push(circ_gbuf_t *circ_buf, void *elem)
{
...
total = circ_buf->push_count - circ_buf->pop_count;
if (total < 0)
total += (2 * circ_buf->size);
...
}
then they are also not thread safe.
Test program which proves that even with one producer and one consumer calculations will go wrong:
#include <unistd.h> /* sleep */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "circular-generic-buffer.h"
struct my_struct {
int a;
char b;
double c;
};
#define BUF_SIZE 100
#define RUN_THREAD 1
CIRC_GBUF_DEF(struct my_struct, my_circ_buf, BUF_SIZE)
#if RUN_THREAD
#include <sched.h>
#include <pthread.h> /* phread_create */
void * push(void * arg)
{
// UNUSED(arg);
int i;
struct my_struct test;
int nr;
int free_space;
printf("push tasks started\n");
//2. One task is pushing BUF_SIZE/2 times
for (i=0; i<BUF_SIZE/2; i++) {
test.a = i;
nr = circ_gbuf_free_space(&my_circ_buf);
/* some calculations */
usleep(i);
/* some calculations */
free_space = circ_gbuf_free_space(&my_circ_buf);
if (nr!=free_space)
printf("+iter=%d pop_count=%d push_count=%d free_space=%d free_space=%d\n", i,
my_circ_buf.pop_count, my_circ_buf.push_count, free_space, nr);
if ( circ_gbuf_push(&my_circ_buf, &test) ) {
printf("*2. Out of space in CB at %d\n", i);
return NULL;
}
}
return NULL;
}
void * pop(void * arg)
{
// UNUSED(arg);
int i;
struct my_struct test;
int nr;
int free_space;
printf("pop tasks started\n");
//2. One task is pushing BUF_SIZE/2 times
for (i=0; i<BUF_SIZE/2; i++) {
if ( circ_gbuf_pop( &my_circ_buf, &test, 0) /*CIRC_GBUF_POP(my_circ_buf, &a[10 + i])*/ ) {
printf("*3. CB is empty at %d\n", i);
return NULL;
}
nr = circ_gbuf_free_space(&my_circ_buf);
/* some calculations */
if( i%2) usleep(i);
/* some calculations */
free_space = circ_gbuf_free_space(&my_circ_buf);
if (nr!=free_space)
printf("-iter=%d pop_count=%d push_count=%d free_space=%d free_space=%d\n", i,
my_circ_buf.pop_count, my_circ_buf.push_count, free_space, nr);
}
return NULL;
}
void * observer(void * arg){
int i;
struct my_struct test;
int nr;
int free_space;
printf("observer tasks started\n");
for (i=0; i<BUF_SIZE; i++) {
if( i%2) usleep(i);
}
return NULL;
}
#endif
int main()
{
int i;
int j;
struct my_struct a[20];
#if RUN_THREAD
/*
pthread_mutex_t mutex;
pthread_cond_t cond;
*/
pthread_t task1;
pthread_t task2;
pthread_t task3;
#endif
struct my_struct test;
test.a= 0;
test.b= 'S';
test.c = 12345.678;
int nr,free_space;
srand(time(NULL));
//1. fill the buffer in half
for (i=0; i<BUF_SIZE/2; i++) {
test.a = i;
if ( circ_gbuf_push(&my_circ_buf, &test) ) {
printf("1. Out of space in CB at %d\n", i);
return -1;
}
}
nr = circ_gbuf_free_space(&my_circ_buf);
/* some calculations */
usleep(200);
/* some calculations */
free_space = circ_gbuf_free_space(&my_circ_buf);
printf("start pop_count=%d push_count=%d free_space=%d free_space=%d\n",
my_circ_buf.pop_count, my_circ_buf.push_count, free_space, nr);
#if 0
//2. One task is pushing BUF_SIZE/2 times
for (i=0; i<BUF_SIZE/2; i++) {
test.a = i;
if ( circ_gbuf_push(&my_circ_buf, &test) ) {
printf("2. Out of space in CB at %d\n", i);
return -1;
}
}
//3. One task is poping BUF_SIZE/2 times
for (i=0; i<BUF_SIZE/2; i++) {
if ( circ_gbuf_pop( &my_circ_buf, &test, 0) /*CIRC_GBUF_POP(my_circ_buf, &a[10 + i])*/ ) {
printf("3. CB is empty at %d\n", i);
return -1;
}
}
printf("Test Passed .pop_count=%d .push_count=%d nr_of_elem=%d\n",
my_circ_buf.pop_count, my_circ_buf.push_count,circ_gbuf_free_space(&my_circ_buf));
#endif
#if RUN_THREAD
printf("ok1!\n");
if( pthread_create(&task1, NULL, push, NULL) != 0)
{
printf("problem:task1\n");
}
printf("ok2!\n");
printf("ok3!\n");
#if 0
if( pthread_create(&task3, NULL, observer, NULL) != 0)
{
printf("problem:task3\n");
}
#endif
printf("ok4!\n");
printf("ok5!\n");
if( pthread_create(&task2, NULL, pop, NULL) != 0)
{
printf("problem:task2\n");
}
printf("ok6!\n");
pthread_join( task1, NULL);
#if 0
pthread_join( task3, NULL);
#endif
pthread_join( task2, NULL);
printf("Test results .pop_count=%d .push_count=%d free_space=%d\n",
my_circ_buf.pop_count, my_circ_buf.push_count,circ_gbuf_free_space(&my_circ_buf));
#endif
return 0;
}
start pop_count=0 push_count=50 free_space=50 free_space=50
ok1!
ok2!
ok3!
ok4!
ok5!
ok6!
pop tasks started
push tasks started
+iter=0 pop_count=4 push_count=50 free_space=54 free_space=52
-iter=3 pop_count=4 push_count=51 free_space=53 free_space=54
+iter=1 pop_count=6 push_count=51 free_space=55 free_space=53
-iter=5 pop_count=6 push_count=52 free_space=54 free_space=55
+iter=2 pop_count=8 push_count=52 free_space=56 free_space=54
-iter=7 pop_count=8 push_count=53 free_space=55 free_space=56
+iter=3 pop_count=10 push_count=53 free_space=57 free_space=55
-iter=9 pop_count=10 push_count=54 free_space=56 free_space=57
+iter=4 pop_count=12 push_count=54 free_space=58 free_space=56
-iter=11 pop_count=12 push_count=55 free_space=57 free_space=58
+iter=5 pop_count=14 push_count=55 free_space=59 free_space=57
-iter=13 pop_count=14 push_count=56 free_space=58 free_space=59
+iter=6 pop_count=16 push_count=56 free_space=60 free_space=58
-iter=15 pop_count=16 push_count=57 free_space=59 free_space=60
+iter=7 pop_count=18 push_count=57 free_space=61 free_space=59
-iter=17 pop_count=18 push_count=58 free_space=60 free_space=61
+iter=8 pop_count=20 push_count=58 free_space=62 free_space=60
-iter=19 pop_count=20 push_count=59 free_space=61 free_space=62
+iter=9 pop_count=22 push_count=59 free_space=63 free_space=61
-iter=21 pop_count=22 push_count=60 free_space=62 free_space=63
+iter=11 pop_count=26 push_count=61 free_space=65 free_space=61
-iter=25 pop_count=26 push_count=62 free_space=64 free_space=65
+iter=12 pop_count=28 push_count=62 free_space=66 free_space=64
-iter=27 pop_count=28 push_count=63 free_space=65 free_space=66
+iter=13 pop_count=30 push_count=63 free_space=67 free_space=65
-iter=29 pop_count=30 push_count=64 free_space=66 free_space=67
+iter=16 pop_count=32 push_count=66 free_space=66 free_space=64
-iter=31 pop_count=32 push_count=68 free_space=64 free_space=66
+iter=18 pop_count=34 push_count=68 free_space=66 free_space=64
-iter=33 pop_count=34 push_count=69 free_space=65 free_space=66
+iter=19 pop_count=36 push_count=69 free_space=67 free_space=65
-iter=35 pop_count=36 push_count=70 free_space=66 free_space=67
+iter=20 pop_count=38 push_count=70 free_space=68 free_space=66
-iter=37 pop_count=38 push_count=71 free_space=67 free_space=68
+iter=21 pop_count=40 push_count=71 free_space=69 free_space=67
-iter=39 pop_count=40 push_count=72 free_space=68 free_space=69
+iter=22 pop_count=42 push_count=72 free_space=70 free_space=68
-iter=41 pop_count=42 push_count=73 free_space=69 free_space=70
+iter=23 pop_count=44 push_count=73 free_space=71 free_space=69
-iter=43 pop_count=44 push_count=75 free_space=69 free_space=71
+iter=25 pop_count=46 push_count=75 free_space=71 free_space=69
-iter=45 pop_count=46 push_count=76 free_space=70 free_space=71
+iter=26 pop_count=48 push_count=76 free_space=72 free_space=70
-iter=47 pop_count=48 push_count=78 free_space=70 free_space=72
+iter=28 pop_count=50 push_count=78 free_space=72 free_space=70
-iter=49 pop_count=50 push_count=79 free_space=71 free_space=72
Test results .pop_count=50 .push_count=100 free_space=50