Last active
June 14, 2025 09:11
-
-
Save diffstorm/b2f1829958ed42a6ce45c3fdeb3eda87 to your computer and use it in GitHub Desktop.
Multi-threaded circular buffer library in C that supports simultaneous reading and writing operations
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Multi-threaded circular buffer library in C that supports simultaneous | |
reading and writing operations. It provides options to overwrite the oldest data | |
when the buffer is full or to skip new data based on a flag. The library includes | |
functions to initialize, write, read, and clean up the circular buffer, and also | |
demonstrates concurrent access with multiple writer and reader threads. | |
The code is written in standard C and can be compiled and executed on various platforms, including Linux, Windows, and macOS. The code does not inherently depend on any specific platform-dependent features, libraries, or APIs. It uses standard C libraries and pthreads for multithreading, which are commonly available on many systems. | |
Author : Eray Ozturk | [email protected] | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <pthread.h> | |
#include <stdbool.h> | |
#include <string.h> | |
#include <unistd.h> // for sleep function | |
#define MAX_WRITE_SIZE 10 | |
typedef struct { | |
char *buffer; | |
int size; // Size of the buffer | |
int head; | |
int tail; | |
bool overwrite; // Flag to enable overwriting or skipping new data | |
pthread_mutex_t mutex; | |
pthread_cond_t not_full; // Condition variable for buffer not being full | |
pthread_cond_t not_empty; // Condition variable for buffer not being empty | |
} CircularBuffer; | |
// Initialize the circular buffer | |
void init_buffer(CircularBuffer *cb, int size, bool overwrite) { | |
cb->size = size; | |
cb->buffer = (char *)malloc(size * sizeof(char)); | |
cb->head = 0; | |
cb->tail = 0; | |
cb->overwrite = overwrite; | |
pthread_mutex_init(&cb->mutex, NULL); | |
pthread_cond_init(&cb->not_full, NULL); | |
pthread_cond_init(&cb->not_empty, NULL); | |
} | |
// Write data to the circular buffer | |
void write_buffer(CircularBuffer *cb, const char *data, int size) { | |
pthread_mutex_lock(&cb->mutex); | |
// Wait until there's enough space in the buffer | |
while ((cb->head + size) % BUFFER_SIZE == cb->tail) { | |
if (cb->overwrite) { | |
cb->tail = (cb->tail + 1) % BUFFER_SIZE; // Overwrite oldest data | |
} else { | |
pthread_mutex_unlock(&cb->mutex); | |
return; // Skip new data when buffer is full and overwrite is disabled | |
} | |
} | |
// Copy data into the buffer | |
for (int i = 0; i < size; i++) { | |
cb->buffer[cb->head] = data[i]; | |
cb->head = (cb->head + 1) % BUFFER_SIZE; | |
} | |
// Signal that buffer is not empty anymore | |
pthread_cond_signal(&cb->not_empty); | |
pthread_mutex_unlock(&cb->mutex); | |
} | |
// Read data from the circular buffer | |
void read_buffer(CircularBuffer *cb, char *data, int size) { | |
pthread_mutex_lock(&cb->mutex); | |
// Wait until there's data available in the buffer | |
while (cb->head == cb->tail) { | |
pthread_cond_wait(&cb->not_empty, &cb->mutex); | |
} | |
// Copy data from the buffer | |
for (int i = 0; i < size; i++) { | |
data[i] = cb->buffer[cb->tail]; | |
cb->tail = (cb->tail + 1) % BUFFER_SIZE; | |
} | |
// Signal that buffer is not full anymore | |
pthread_cond_signal(&cb->not_full); | |
pthread_mutex_unlock(&cb->mutex); | |
} | |
// Check if the circular buffer is full | |
bool is_buffer_full(CircularBuffer *cb) { | |
return ((cb->head + 1) % cb->size == cb->tail); | |
} | |
// Check if the circular buffer is empty | |
bool is_buffer_empty(CircularBuffer *cb) { | |
return (cb->head == cb->tail); | |
} | |
// Calculate available space in the circular buffer | |
int available_space(CircularBuffer *cb) { | |
return (cb->size + cb->tail - cb->head - 1) % cb->size; | |
} | |
// Check if there is enough space to write data of given size | |
bool can_write(CircularBuffer *cb, int data_size) { | |
return (available_space(cb) >= data_size); | |
} | |
// Cleanup resources of the circular buffer | |
void cleanup_buffer(CircularBuffer *cb) { | |
free(cb->buffer); | |
pthread_mutex_destroy(&cb->mutex); | |
pthread_cond_destroy(&cb->not_full); | |
pthread_cond_destroy(&cb->not_empty); | |
} | |
// Writer thread function | |
void *writer_thread(void *arg) { | |
CircularBuffer *cb = (CircularBuffer *)arg; | |
for (int i = 0; i < 20; i++) { | |
char data[MAX_WRITE_SIZE]; | |
snprintf(data, MAX_WRITE_SIZE, "Data%d", i); | |
int data_size = strlen(data); | |
write_buffer(cb, data, data_size); | |
printf("Thread %lu wrote: %s\n", pthread_self(), data); | |
usleep(100000); // Simulate some delay | |
} | |
return NULL; | |
} | |
// Reader thread function | |
void *reader_thread(void *arg) { | |
CircularBuffer *cb = (CircularBuffer *)arg; | |
for (int i = 0; i < 20; i++) { | |
char data[MAX_WRITE_SIZE]; | |
read_buffer(cb, data, MAX_WRITE_SIZE); | |
printf("Thread %lu read: %s\n", pthread_self(), data); | |
usleep(200000); // Simulate some delay | |
} | |
return NULL; | |
} | |
int main() { | |
// Initialize circular buffers with different overwrite settings | |
CircularBuffer cb_overwrite, cb_skip; | |
init_buffer(&cb_overwrite, 50, true); // Enable overwrite | |
init_buffer(&cb_skip, 80, false); // Disable overwrite | |
// Create writer and reader threads | |
pthread_t writers[5], readers[2]; | |
for (int i = 0; i < 5; i++) { | |
pthread_create(&writers[i], NULL, writer_thread, &cb_overwrite); | |
} | |
for (int i = 0; i < 2; i++) { | |
pthread_create(&readers[i], NULL, reader_thread, &cb_skip); | |
} | |
// Wait for threads to finish | |
for (int i = 0; i < 5; i++) { | |
pthread_join(writers[i], NULL); | |
} | |
for (int i = 0; i < 2; i++) { | |
pthread_join(readers[i], NULL); | |
} | |
// Clean up resources | |
cleanup_buffer(&cb_overwrite); | |
cleanup_buffer(&cb_skip); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment