Channel Buffering in C
The concept of buffered channels in C can be simulated using a thread-safe queue. We’ll use a simple array-based queue implementation with mutex locks for thread safety.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#define BUFFER_SIZE 2
typedef struct {
char* data[BUFFER_SIZE];
int front;
int rear;
int count;
pthread_mutex_t mutex;
} BufferedQueue;
void initQueue(BufferedQueue* queue) {
queue->front = 0;
queue->rear = -1;
queue->count = 0;
pthread_mutex_init(&queue->mutex, NULL);
}
void enqueue(BufferedQueue* queue, const char* message) {
pthread_mutex_lock(&queue->mutex);
if (queue->count < BUFFER_SIZE) {
queue->rear = (queue->rear + 1) % BUFFER_SIZE;
queue->data[queue->rear] = strdup(message);
queue->count++;
}
pthread_mutex_unlock(&queue->mutex);
}
char* dequeue(BufferedQueue* queue) {
char* message = NULL;
pthread_mutex_lock(&queue->mutex);
if (queue->count > 0) {
message = queue->data[queue->front];
queue->front = (queue->front + 1) % BUFFER_SIZE;
queue->count--;
}
pthread_mutex_unlock(&queue->mutex);
return message;
}
int main() {
BufferedQueue messages;
initQueue(&messages);
// Because this queue is buffered, we can send these
// values into the queue without a corresponding
// concurrent receive.
enqueue(&messages, "buffered");
enqueue(&messages, "queue");
// Later we can receive these two values as usual.
char* msg1 = dequeue(&messages);
char* msg2 = dequeue(&messages);
if (msg1) {
printf("%s\n", msg1);
free(msg1);
}
if (msg2) {
printf("%s\n", msg2);
free(msg2);
}
return 0;
}
This C program demonstrates a concept similar to buffered channels using a thread-safe queue. Here’s how it works:
We define a
BufferedQueue
structure that holds an array of strings, along with front and rear indices, a count, and a mutex for thread safety.The
initQueue
function initializes the queue and its mutex.The
enqueue
function adds a message to the queue if it’s not full. It uses the mutex to ensure thread safety.The
dequeue
function removes and returns a message from the queue if it’s not empty. It also uses the mutex for thread safety.In the
main
function, we create a buffered queue that can hold up to 2 messages.We enqueue two messages into the queue without needing a corresponding receive operation.
Later, we dequeue and print these two messages.
To compile and run this program:
$ gcc -o buffered_queue buffered_queue.c -lpthread
$ ./buffered_queue
buffered
queue
This example demonstrates how to implement a concept similar to buffered channels in C using a thread-safe queue. While C doesn’t have built-in support for such high-level concurrency primitives, we can create similar functionality using lower-level constructs like mutexes and condition variables.