#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#define BUFFER_SIZE 25
pthread_mutex_t rand_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t prod_cond = PTHREAD_COND_INITIALIZER;
pthread_cond_t cons_cond = PTHREAD_COND_INITIALIZER;
typedef struct {
char *buffer;
size_t capacity;
size_t read_index;
size_t write_index;
pthread_mutex_t mutex;
} CircularBuffer;
CircularBuffer cb;
void cb_init(CircularBuffer *cb, size_t capacity)
{
cb->buffer = (char*)malloc(capacity);
if (cb->buffer == NULL) {
perror("malloc rand pool");
exit(EXIT_FAILURE);
}
cb->capacity = capacity;
cb->read_index = 0;
cb->write_index = 0;
pthread_mutex_init(&cb->mutex, NULL);
}
void cb_destroy(CircularBuffer *cb)
{
if (cb->buffer)
free(cb->buffer);
cb->buffer = NULL;
pthread_mutex_destroy(&cb->mutex);
}
int cb_write(CircularBuffer *cb, const char *data, size_t len)
{
pthread_mutex_lock(&cb->mutex);
size_t free_space = (cb->read_index + cb->capacity - cb->write_index - 1) % cb->capacity;
if (free_space <= 0) {
pthread_mutex_unlock(&cb->mutex);
return -1;
}
len = len < free_space ? len : free_space;
size_t part1 = cb->capacity - cb->write_index;
if (part1 >= len) {
memcpy(cb->buffer + cb->write_index, data, len);
} else {
memcpy(cb->buffer + cb->write_index, data, part1);
memcpy(cb->buffer, data + part1, len - part1);
}
cb->write_index = (cb->write_index + len) % cb->capacity;
pthread_mutex_unlock(&cb->mutex);
return len;
}
int cb_read(CircularBuffer *cb, char *data, size_t len)
{
pthread_mutex_lock(&cb->mutex);
size_t available_data = (cb->write_index + cb->capacity - cb->read_index) % cb->capacity;
if (available_data < len) {
pthread_mutex_unlock(&cb->mutex);
return -1;
}
size_t part1 = cb->capacity - cb->read_index;
if (part1 >= len) {
memcpy(data, cb->buffer + cb->read_index, len);
} else {
memcpy(data, cb->buffer + cb->read_index, part1);
memcpy(data + part1, cb->buffer, len - part1);
}
cb->read_index = (cb->read_index + len) % cb->capacity;
pthread_mutex_unlock(&cb->mutex);
return len;
}
void *func_producer(void *arg)
{
arg = arg;
struct timespec tv;
// Write some data
ssize_t written;
char test_str[] = "0123456789";
tv.tv_sec = 1;
while(1)
{
pthread_mutex_lock(&rand_mutex);
pthread_cond_timedwait(&prod_cond, &rand_mutex, &tv);
//pthread_cond_wait(&prod_cond, &rand_mutex);
//sleep(1);
while (1)
{
written = cb_write(&cb, test_str, strlen(test_str));
if(written <= 0)
{
//pthread_cond_signal(&cons_cond);
pthread_cond_broadcast(&cons_cond);
printf("error: Wrote %ld bytes\n", written);
break;
}
printf("Wrote %ld bytes\n", written);
}
pthread_mutex_unlock(&rand_mutex);
}
return NULL;
}
void *func_consumer(void *arg)
{
arg = arg;
struct timespec tv;
// Read the data back
ssize_t read_len;
char read_buf[20];
tv.tv_sec = 1;
while(1)
{
//sleep(1);
pthread_mutex_lock(&rand_mutex);
pthread_cond_timedwait(&cons_cond, &rand_mutex, &tv);
//pthread_cond_wait(&cons_cond, &rand_mutex);
while(1)
{
memset(read_buf, 0, sizeof(read_buf));
read_len = cb_read(&cb, read_buf, 10);
if(read_len <=0)
{
//pthread_cond_signal(&prod_cond);
pthread_cond_broadcast(&prod_cond);
//sleep(1);
printf("error: Read %ld bytes: '%s'\n", read_len, read_buf);
break;
}
printf("Read %ld bytes: '%s' out\n", read_len, read_buf);
}
pthread_mutex_unlock(&rand_mutex);
}
return NULL;
}
// gcc -g -O0 -std=c99 -Wall -Wextra -pedantic -pthread test.c -o string_ring_buffer
// Example usage
int main() {
int i;
pthread_t t_prod[10];
pthread_t t_cons[10];
cb_init(&cb, BUFFER_SIZE);
for(i=0; i<5; i++)
{
pthread_create(&t_prod[i], NULL, func_producer, NULL);
pthread_create(&t_cons[i], NULL, func_consumer, NULL);
}
for(i=0; i<5; i++)
{
pthread_join(t_prod[i], NULL);
pthread_join(t_cons[i], NULL);
}
// Clean up
cb_destroy(&cb);
return 0;
}